diff options
Diffstat (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c')
| -rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 343 |
1 files changed, 197 insertions, 146 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 38bf111e5f9b..4b255e25e4a1 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -736,6 +736,10 @@ static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg, if (msg->curchunk_idx >= msg->curchunk_len) { /* do CRC */ crc4 = drm_dp_msg_data_crc4(msg->chunk, msg->curchunk_len - 1); + if (crc4 != msg->chunk[msg->curchunk_len - 1]) + print_hex_dump(KERN_DEBUG, "wrong crc", + DUMP_PREFIX_NONE, 16, 1, + msg->chunk, msg->curchunk_len, false); /* copy chunk into bigger msg */ memcpy(&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len - 1); msg->curlen += msg->curchunk_len - 1; @@ -1035,7 +1039,8 @@ static bool drm_dp_sideband_parse_req(struct drm_dp_sideband_msg_rx *raw, } } -static int build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes, u8 *bytes) +static void build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, + u8 port_num, u32 offset, u8 num_bytes, u8 *bytes) { struct drm_dp_sideband_msg_req_body req; @@ -1045,17 +1050,14 @@ static int build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 req.u.dpcd_write.num_bytes = num_bytes; req.u.dpcd_write.bytes = bytes; drm_dp_encode_sideband_req(&req, msg); - - return 0; } -static int build_link_address(struct drm_dp_sideband_msg_tx *msg) +static void build_link_address(struct drm_dp_sideband_msg_tx *msg) { struct drm_dp_sideband_msg_req_body req; req.req_type = DP_LINK_ADDRESS; drm_dp_encode_sideband_req(&req, msg); - return 0; } static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg) @@ -1067,7 +1069,8 @@ static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg) return 0; } -static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int port_num) +static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, + int port_num) { struct drm_dp_sideband_msg_req_body req; @@ -1078,10 +1081,11 @@ static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int por return 0; } -static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_num, - u8 vcpi, uint16_t pbn, - u8 number_sdp_streams, - u8 *sdp_stream_sink) +static void build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, + int port_num, + u8 vcpi, uint16_t pbn, + u8 number_sdp_streams, + u8 *sdp_stream_sink) { struct drm_dp_sideband_msg_req_body req; memset(&req, 0, sizeof(req)); @@ -1094,11 +1098,10 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n number_sdp_streams); drm_dp_encode_sideband_req(&req, msg); msg->path_msg = true; - return 0; } -static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, - int port_num, bool power_up) +static void build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, + int port_num, bool power_up) { struct drm_dp_sideband_msg_req_body req; @@ -1110,7 +1113,6 @@ static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, req.u.port_num.port_number = port_num; drm_dp_encode_sideband_req(&req, msg); msg->path_msg = true; - return 0; } static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, @@ -1935,73 +1937,90 @@ static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port, return parent_lct + 1; } -static int drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt) +static bool drm_dp_mst_is_dp_mst_end_device(u8 pdt, bool mcs) +{ + switch (pdt) { + case DP_PEER_DEVICE_DP_LEGACY_CONV: + case DP_PEER_DEVICE_SST_SINK: + return true; + case DP_PEER_DEVICE_MST_BRANCHING: + /* For sst branch device */ + if (!mcs) + return true; + + return false; + } + return true; +} + +static int +drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt, + bool new_mcs) { struct drm_dp_mst_topology_mgr *mgr = port->mgr; struct drm_dp_mst_branch *mstb; u8 rad[8], lct; int ret = 0; - if (port->pdt == new_pdt) + if (port->pdt == new_pdt && port->mcs == new_mcs) return 0; /* Teardown the old pdt, if there is one */ - switch (port->pdt) { - case DP_PEER_DEVICE_DP_LEGACY_CONV: - case DP_PEER_DEVICE_SST_SINK: - /* - * If the new PDT would also have an i2c bus, don't bother - * with reregistering it - */ - if (new_pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || - new_pdt == DP_PEER_DEVICE_SST_SINK) { - port->pdt = new_pdt; - return 0; - } + if (port->pdt != DP_PEER_DEVICE_NONE) { + if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) { + /* + * If the new PDT would also have an i2c bus, + * don't bother with reregistering it + */ + if (new_pdt != DP_PEER_DEVICE_NONE && + drm_dp_mst_is_dp_mst_end_device(new_pdt, new_mcs)) { + port->pdt = new_pdt; + port->mcs = new_mcs; + return 0; + } - /* remove i2c over sideband */ - drm_dp_mst_unregister_i2c_bus(&port->aux); - break; - case DP_PEER_DEVICE_MST_BRANCHING: - mutex_lock(&mgr->lock); - drm_dp_mst_topology_put_mstb(port->mstb); - port->mstb = NULL; - mutex_unlock(&mgr->lock); - break; + /* remove i2c over sideband */ + drm_dp_mst_unregister_i2c_bus(&port->aux); + } else { + mutex_lock(&mgr->lock); + drm_dp_mst_topology_put_mstb(port->mstb); + port->mstb = NULL; + mutex_unlock(&mgr->lock); + } } port->pdt = new_pdt; - switch (port->pdt) { - case DP_PEER_DEVICE_DP_LEGACY_CONV: - case DP_PEER_DEVICE_SST_SINK: - /* add i2c over sideband */ - ret = drm_dp_mst_register_i2c_bus(&port->aux); - break; + port->mcs = new_mcs; - case DP_PEER_DEVICE_MST_BRANCHING: - lct = drm_dp_calculate_rad(port, rad); - mstb = drm_dp_add_mst_branch_device(lct, rad); - if (!mstb) { - ret = -ENOMEM; - DRM_ERROR("Failed to create MSTB for port %p", port); - goto out; - } + if (port->pdt != DP_PEER_DEVICE_NONE) { + if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) { + /* add i2c over sideband */ + ret = drm_dp_mst_register_i2c_bus(&port->aux); + } else { + lct = drm_dp_calculate_rad(port, rad); + mstb = drm_dp_add_mst_branch_device(lct, rad); + if (!mstb) { + ret = -ENOMEM; + DRM_ERROR("Failed to create MSTB for port %p", + port); + goto out; + } - mutex_lock(&mgr->lock); - port->mstb = mstb; - mstb->mgr = port->mgr; - mstb->port_parent = port; + mutex_lock(&mgr->lock); + port->mstb = mstb; + mstb->mgr = port->mgr; + mstb->port_parent = port; - /* - * Make sure this port's memory allocation stays - * around until its child MSTB releases it - */ - drm_dp_mst_get_port_malloc(port); - mutex_unlock(&mgr->lock); + /* + * Make sure this port's memory allocation stays + * around until its child MSTB releases it + */ + drm_dp_mst_get_port_malloc(port); + mutex_unlock(&mgr->lock); - /* And make sure we send a link address for this */ - ret = 1; - break; + /* And make sure we send a link address for this */ + ret = 1; + } } out: @@ -2044,7 +2063,7 @@ ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, * sideband messaging as drm_dp_dpcd_write() does for local * devices via actual AUX CH. * - * Return: 0 on success, negative error code on failure. + * Return: number of bytes written on success, negative error code on failure. */ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, void *buffer, size_t size) @@ -2056,29 +2075,27 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, offset, size, buffer); } -static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) +static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) { - int ret; + int ret = 0; memcpy(mstb->guid, guid, 16); if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) { if (mstb->port_parent) { - ret = drm_dp_send_dpcd_write( - mstb->mgr, - mstb->port_parent, - DP_GUID, - 16, - mstb->guid); + ret = drm_dp_send_dpcd_write(mstb->mgr, + mstb->port_parent, + DP_GUID, 16, mstb->guid); } else { - - ret = drm_dp_dpcd_write( - mstb->mgr->aux, - DP_GUID, - mstb->guid, - 16); + ret = drm_dp_dpcd_write(mstb->mgr->aux, + DP_GUID, mstb->guid, 16); } } + + if (ret < 16 && ret > 0) + return -EPROTO; + + return ret == 16 ? 0 : ret; } static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, @@ -2154,15 +2171,14 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb, goto error; } - if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV || - port->pdt == DP_PEER_DEVICE_SST_SINK) && - port->port_num >= DP_MST_LOGICAL_PORT_0) { + if (port->pdt != DP_PEER_DEVICE_NONE && + drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) { port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); drm_connector_set_tile_property(port->connector); } - mgr->cbs->register_connector(port->connector); + drm_connector_register(port->connector); return; error: @@ -2224,6 +2240,7 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_port *port; int old_ddps = 0, ret; u8 new_pdt = DP_PEER_DEVICE_NONE; + bool new_mcs = 0; bool created = false, send_link_addr = false, changed = false; port = drm_dp_get_port(mstb, port_msg->port_number); @@ -2268,7 +2285,7 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, port->input = port_msg->input_port; if (!port->input) new_pdt = port_msg->peer_device_type; - port->mcs = port_msg->mcs; + new_mcs = port_msg->mcs; port->ddps = port_msg->ddps; port->ldps = port_msg->legacy_device_plug_status; port->dpcd_rev = port_msg->dpcd_revision; @@ -2296,7 +2313,7 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, } } - ret = drm_dp_port_set_pdt(port, new_pdt); + ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs); if (ret == 1) { send_link_addr = true; } else if (ret < 0) { @@ -2310,7 +2327,8 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb, * we're coming out of suspend. In this case, always resend the link * address if there's an MSTB on this port */ - if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING) + if (!created && port->pdt == DP_PEER_DEVICE_MST_BRANCHING && + port->mcs) send_link_addr = true; if (port->connector) @@ -2347,6 +2365,7 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_port *port; int old_ddps, old_input, ret, i; u8 new_pdt; + bool new_mcs; bool dowork = false, create_connector = false; port = drm_dp_get_port(mstb, conn_stat->port_number); @@ -2378,7 +2397,6 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb, old_ddps = port->ddps; old_input = port->input; port->input = conn_stat->input_port; - port->mcs = conn_stat->message_capability_status; port->ldps = conn_stat->legacy_device_plug_status; port->ddps = conn_stat->displayport_device_plug_status; @@ -2391,8 +2409,8 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb, } new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat->peer_device_type; - - ret = drm_dp_port_set_pdt(port, new_pdt); + new_mcs = conn_stat->message_capability_status; + ret = drm_dp_port_set_pdt(port, new_pdt, new_mcs); if (ret == 1) { dowork = true; } else if (ret < 0) { @@ -2627,7 +2645,8 @@ static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, return false; } -static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes) +static void build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, + u8 port_num, u32 offset, u8 num_bytes) { struct drm_dp_sideband_msg_req_body req; @@ -2636,8 +2655,6 @@ static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 req.u.dpcd_read.dpcd_address = offset; req.u.dpcd_read.num_bytes = num_bytes; drm_dp_encode_sideband_req(&req, msg); - - return 0; } static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr, @@ -2863,7 +2880,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_link_address_ack_reply *reply; struct drm_dp_mst_port *port, *tmp; - int i, len, ret, port_mask = 0; + int i, ret, port_mask = 0; bool changed = false; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); @@ -2871,7 +2888,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; txmsg->dst = mstb; - len = build_link_address(txmsg); + build_link_address(txmsg); mstb->link_address_sent = true; drm_dp_queue_down_tx(mgr, txmsg); @@ -2892,7 +2909,15 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, DRM_DEBUG_KMS("link address reply: %d\n", reply->nports); drm_dp_dump_link_address(reply); - drm_dp_check_mstb_guid(mstb, reply->guid); + ret = drm_dp_check_mstb_guid(mstb, reply->guid); + if (ret) { + char buf[64]; + + drm_dp_mst_rad_to_str(mstb->rad, mstb->lct, buf, sizeof(buf)); + DRM_ERROR("GUID check on %s failed: %d\n", + buf, ret); + goto out; + } for (i = 0; i < reply->nports; i++) { port_mask |= BIT(reply->ports[i].port_number); @@ -2933,14 +2958,14 @@ void drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb) { struct drm_dp_sideband_msg_tx *txmsg; - int len, ret; + int ret; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) return; txmsg->dst = mstb; - len = build_clear_payload_id_table(txmsg); + build_clear_payload_id_table(txmsg); drm_dp_queue_down_tx(mgr, txmsg); @@ -2958,7 +2983,6 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, { struct drm_dp_enum_path_resources_ack_reply *path_res; struct drm_dp_sideband_msg_tx *txmsg; - int len; int ret; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); @@ -2966,7 +2990,7 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; txmsg->dst = mstb; - len = build_enum_path_resources(txmsg, port->port_num); + build_enum_path_resources(txmsg, port->port_num); drm_dp_queue_down_tx(mgr, txmsg); @@ -3050,7 +3074,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, { struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; - int len, ret, port_num; + int ret, port_num; u8 sinks[DRM_DP_MAX_SDP_STREAMS]; int i; @@ -3075,9 +3099,9 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, sinks[i] = i; txmsg->dst = mstb; - len = build_allocate_payload(txmsg, port_num, - id, - pbn, port->num_sdp_streams, sinks); + build_allocate_payload(txmsg, port_num, + id, + pbn, port->num_sdp_streams, sinks); drm_dp_queue_down_tx(mgr, txmsg); @@ -3106,7 +3130,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up) { struct drm_dp_sideband_msg_tx *txmsg; - int len, ret; + int ret; port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) @@ -3119,7 +3143,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, } txmsg->dst = port->parent; - len = build_power_updown_phy(txmsg, port->port_num, power_up); + build_power_updown_phy(txmsg, port->port_num, power_up); drm_dp_queue_down_tx(mgr, txmsg); ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg); @@ -3341,7 +3365,6 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int offset, int size, u8 *bytes) { - int len; int ret = 0; struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; @@ -3356,7 +3379,7 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, goto fail_put; } - len = build_dpcd_read(txmsg, port->port_num, offset, size); + build_dpcd_read(txmsg, port->port_num, offset, size); txmsg->dst = port->parent; drm_dp_queue_down_tx(mgr, txmsg); @@ -3394,7 +3417,6 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int offset, int size, u8 *bytes) { - int len; int ret; struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; @@ -3409,18 +3431,15 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, goto fail_put; } - len = build_dpcd_write(txmsg, port->port_num, offset, size, bytes); + build_dpcd_write(txmsg, port->port_num, offset, size, bytes); txmsg->dst = mstb; drm_dp_queue_down_tx(mgr, txmsg); ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); - if (ret > 0) { - if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) - ret = -EIO; - else - ret = 0; - } + if (ret > 0 && txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) + ret = -EIO; + kfree(txmsg); fail_put: drm_dp_mst_topology_put_mstb(mstb); @@ -3481,9 +3500,9 @@ static int drm_dp_get_vc_payload_bw(u8 dp_link_bw, u8 dp_link_count) int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state) { int ret = 0; - int i = 0; struct drm_dp_mst_branch *mstb = NULL; + mutex_lock(&mgr->payload_lock); mutex_lock(&mgr->lock); if (mst_state == mgr->mst_state) goto out_unlock; @@ -3491,6 +3510,8 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms mgr->mst_state = mst_state; /* set the device into MST mode */ if (mst_state) { + struct drm_dp_payload reset_pay; + WARN_ON(mgr->mst_primary); /* get dpcd info */ @@ -3520,17 +3541,15 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms drm_dp_mst_topology_get_mstb(mgr->mst_primary); ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, - DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); - if (ret < 0) { + DP_MST_EN | + DP_UP_REQ_EN | + DP_UPSTREAM_IS_SRC); + if (ret < 0) goto out_unlock; - } - { - struct drm_dp_payload reset_pay; - reset_pay.start_slot = 0; - reset_pay.num_slots = 0x3f; - drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); - } + reset_pay.start_slot = 0; + reset_pay.num_slots = 0x3f; + drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); queue_work(system_long_wq, &mgr->work); @@ -3542,27 +3561,19 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms /* this can fail if the device is gone */ drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0); ret = 0; - mutex_lock(&mgr->payload_lock); - memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload)); + memset(mgr->payloads, 0, + mgr->max_payloads * sizeof(mgr->payloads[0])); + memset(mgr->proposed_vcpis, 0, + mgr->max_payloads * sizeof(mgr->proposed_vcpis[0])); mgr->payload_mask = 0; set_bit(0, &mgr->payload_mask); - for (i = 0; i < mgr->max_payloads; i++) { - struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; - - if (vcpi) { - vcpi->vcpi = 0; - vcpi->num_slots = 0; - } - mgr->proposed_vcpis[i] = NULL; - } mgr->vcpi_mask = 0; - mutex_unlock(&mgr->payload_lock); - mgr->payload_id_table_cleared = false; } out_unlock: mutex_unlock(&mgr->lock); + mutex_unlock(&mgr->payload_lock); if (mstb) drm_dp_mst_topology_put_mstb(mstb); return ret; @@ -3663,7 +3674,12 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); goto out_fail; } - drm_dp_check_mstb_guid(mgr->mst_primary, guid); + + ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid); + if (ret) { + DRM_DEBUG_KMS("check mstb failed - undocked during suspend?\n"); + goto out_fail; + } /* * For the final step of resuming the topology, we need to bring the @@ -3690,7 +3706,7 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up) { int len; u8 replyblock[32]; - int replylen, origlen, curreply; + int replylen, curreply; int ret; struct drm_dp_sideband_msg_rx *msg; int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE : DP_SIDEBAND_MSG_DOWN_REP_BASE; @@ -3710,7 +3726,6 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up) } replylen = msg->curchunk_len + msg->curchunk_hdrlen; - origlen = replylen; replylen -= len; curreply = len; while (replylen > 0) { @@ -3820,7 +3835,8 @@ drm_dp_mst_process_up_req(struct drm_dp_mst_topology_mgr *mgr, else if (msg->req_type == DP_RESOURCE_STATUS_NOTIFY) guid = msg->u.resource_stat.guid; - mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid); + if (guid) + mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid); } else { mstb = drm_dp_get_mst_branch_device(mgr, hdr->lct, hdr->rad); } @@ -4007,6 +4023,8 @@ drm_dp_mst_detect_port(struct drm_connector *connector, switch (port->pdt) { case DP_PEER_DEVICE_NONE: case DP_PEER_DEVICE_MST_BRANCHING: + if (!port->mcs) + ret = connector_status_connected; break; case DP_PEER_DEVICE_SST_SINK: @@ -4603,15 +4621,34 @@ void drm_dp_mst_dump_topology(struct seq_file *m, int ret; ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE); + if (ret) { + seq_printf(m, "dpcd read failed\n"); + goto out; + } seq_printf(m, "dpcd: %*ph\n", DP_RECEIVER_CAP_SIZE, buf); + ret = drm_dp_dpcd_read(mgr->aux, DP_FAUX_CAP, buf, 2); + if (ret) { + seq_printf(m, "faux/mst read failed\n"); + goto out; + } seq_printf(m, "faux/mst: %*ph\n", 2, buf); + ret = drm_dp_dpcd_read(mgr->aux, DP_MSTM_CTRL, buf, 1); + if (ret) { + seq_printf(m, "mst ctrl read failed\n"); + goto out; + } seq_printf(m, "mst ctrl: %*ph\n", 1, buf); /* dump the standard OUI branch header */ ret = drm_dp_dpcd_read(mgr->aux, DP_BRANCH_OUI, buf, DP_BRANCH_OUI_HEADER_SIZE); + if (ret) { + seq_printf(m, "branch oui read failed\n"); + goto out; + } seq_printf(m, "branch oui: %*phN devid: ", 3, buf); + for (i = 0x3; i < 0x8 && buf[i]; i++) seq_printf(m, "%c", buf[i]); seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n", @@ -4620,6 +4657,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, "payload table: %*ph\n", DP_PAYLOAD_TABLE_SIZE, buf); } +out: mutex_unlock(&mgr->lock); } @@ -4635,13 +4673,25 @@ static void drm_dp_tx_work(struct work_struct *work) mutex_unlock(&mgr->qlock); } +static inline void drm_dp_destroy_connector(struct drm_dp_mst_port *port) +{ + if (!port->connector) + return; + + if (port->mgr->cbs->destroy_connector) { + port->mgr->cbs->destroy_connector(port->mgr, port->connector); + } else { + drm_connector_unregister(port->connector); + drm_connector_put(port->connector); + } +} + static inline void drm_dp_delayed_destroy_port(struct drm_dp_mst_port *port) { - if (port->connector) - port->mgr->cbs->destroy_connector(port->mgr, port->connector); + drm_dp_destroy_connector(port); - drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE); + drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs); drm_dp_mst_put_port_malloc(port); } @@ -5440,7 +5490,8 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) if (drm_dp_read_desc(port->mgr->aux, &desc, true)) return NULL; - if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && + if (drm_dp_has_quirk(&desc, 0, + DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && port->parent == port->mgr->mst_primary) { u8 downstreamport; |