Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd934320 authored by Mykola Lysenko's avatar Mykola Lysenko Committed by Alex Deucher
Browse files

drm/dp/mst: process broadcast messages correctly



In case broadcast message received in UP request,
RAD cannot be used to identify message originator.
Message should be parsed, originator should be found
by GUID from parsed message.

Also reply with broadcast in case broadcast message
received (for now it is always broadcast)

Acked-by: default avatarDave Airlie <airlied@gmail.com>
Signed-off-by: default avatarMykola Lysenko <Mykola.Lysenko@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent 6a53b313
Loading
Loading
Loading
Loading
+84 −11
Original line number Diff line number Diff line
@@ -1215,6 +1215,50 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_
	return mstb;
}

static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
	struct drm_dp_mst_branch *mstb,
	uint8_t *guid)
{
	struct drm_dp_mst_branch *found_mstb;
	struct drm_dp_mst_port *port;

	list_for_each_entry(port, &mstb->ports, next) {
		if (!port->mstb)
			continue;

		if (port->guid_valid && memcmp(port->guid, guid, 16) == 0)
			return port->mstb;

		found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);

		if (found_mstb)
			return found_mstb;
	}

	return NULL;
}

static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid(
	struct drm_dp_mst_topology_mgr *mgr,
	uint8_t *guid)
{
	struct drm_dp_mst_branch *mstb;

	/* find the port by iterating down */
	mutex_lock(&mgr->lock);

	if (mgr->guid_valid && memcmp(mgr->guid, guid, 16) == 0)
		mstb = mgr->mst_primary;
	else
		mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);

	if (mstb)
		kref_get(&mstb->kref);

	mutex_unlock(&mgr->lock);
	return mstb;
}

static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
					       struct drm_dp_mst_branch *mstb)
{
@@ -1325,6 +1369,7 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr,
				  struct drm_dp_sideband_msg_tx *txmsg)
{
	struct drm_dp_mst_branch *mstb = txmsg->dst;
	u8 req_type;

	/* both msg slots are full */
	if (txmsg->seqno == -1) {
@@ -1341,6 +1386,12 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr,
			txmsg->seqno = 1;
		mstb->tx_slots[txmsg->seqno] = txmsg;
	}

	req_type = txmsg->msg[0] & 0x7f;
	if (req_type == DP_CONNECTION_STATUS_NOTIFY ||
		req_type == DP_RESOURCE_STATUS_NOTIFY)
		hdr->broadcast = 1;
	else
		hdr->broadcast = 0;
	hdr->path_msg = txmsg->path_msg;
	hdr->lct = mstb->lct;
@@ -2157,8 +2208,10 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)

	if (mgr->up_req_recv.have_eomt) {
		struct drm_dp_sideband_msg_req_body msg;
		struct drm_dp_mst_branch *mstb;
		struct drm_dp_mst_branch *mstb = NULL;
		bool seqno;

		if (!mgr->up_req_recv.initial_hdr.broadcast) {
			mstb = drm_dp_get_mst_branch_device(mgr,
							    mgr->up_req_recv.initial_hdr.lct,
							    mgr->up_req_recv.initial_hdr.rad);
@@ -2167,18 +2220,38 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
				memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
				return 0;
			}
		}

		seqno = mgr->up_req_recv.initial_hdr.seqno;
		drm_dp_sideband_parse_req(&mgr->up_req_recv, &msg);

		if (msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
			drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
			drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);

			if (!mstb)
				mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.conn_stat.guid);

			if (!mstb) {
				DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
				memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
				return 0;
			}

			drm_dp_update_port(mstb, &msg.u.conn_stat);
			DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
			(*mgr->cbs->hotplug)(mgr);

		} else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
			drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
			drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
			if (!mstb)
				mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.resource_stat.guid);

			if (!mstb) {
				DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
				memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
				return 0;
			}

			DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
		}