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

Commit 51523be1 authored by Sriharsha Allenki's avatar Sriharsha Allenki
Browse files

usb: pd: Prevent sending accept for DR_SWAP after timeout



In a scenario where the device has failed to send ACCEPT
for a DR_SWAP request within tSenderResponse, it's port
partner does not swap it's own role. But this device goes
ahead and sends ACCEPT and also swaps it's data role
leading to an invalid state where both the port partners
are in the same data role. And the port partner treats
this ACCEPT as an invalid message and issues a soft
reset.

Fix this by not sending an ACCEPT after the tSenderResponse
(with a buffer) from receiving a DR_SWAP request and
preventing from switching the data role.

Change-Id: I77a48acd876459b64b97ae18515069ae6218e8b6
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent 9c8c9685
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -240,6 +240,7 @@ static void *usbpd_ipc_log;
#define VDM_BUSY_TIME		50
#define VCONN_ON_TIME		100
#define SINK_TX_TIME		16
#define DR_SWAP_RESPONSE_TIME	20

/* tPSHardReset + tSafe0V */
#define SNK_HARD_RESET_VBUS_OFF_TIME	(35 + 650)
@@ -395,6 +396,8 @@ struct usbpd {
	enum usbpd_state	current_state;
	bool			hard_reset_recvd;
	ktime_t			hard_reset_recvd_time;
	ktime_t			dr_swap_recvd_time;

	struct list_head	rx_q;
	spinlock_t		rx_lock;
	struct rx_msg		*rx_ext_msg;
@@ -1155,6 +1158,9 @@ static void phy_msg_received(struct usbpd *pd, enum pd_sop_type sop,
		return;
	}

	if (IS_CTRL(rx_msg, MSG_DR_SWAP))
		pd->dr_swap_recvd_time = ktime_get();

	spin_lock_irqsave(&pd->rx_lock, flags);
	list_add_tail(&rx_msg->entry, &pd->rx_q);
	spin_unlock_irqrestore(&pd->rx_lock, flags);
@@ -2466,6 +2472,7 @@ static void usbpd_sm(struct work_struct *w)
	int ret, ms;
	struct rx_msg *rx_msg = NULL;
	unsigned long flags;
	s64 dr_swap_delta;

	usbpd_dbg(&pd->dev, "handle state %s\n",
			usbpd_state_strings[pd->current_state]);
@@ -2746,6 +2753,14 @@ static void usbpd_sm(struct work_struct *w)
				break;
			}

			dr_swap_delta = ktime_ms_delta(ktime_get(),
						pd->dr_swap_recvd_time);
			if (dr_swap_delta > DR_SWAP_RESPONSE_TIME) {
				usbpd_err(&pd->dev, "DR swap timedout(%lld), do not send ACCEPT\n",
								dr_swap_delta);
				break;
			}

			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);
@@ -3028,6 +3043,14 @@ static void usbpd_sm(struct work_struct *w)
				break;
			}

			dr_swap_delta = ktime_ms_delta(ktime_get(),
						pd->dr_swap_recvd_time);
			if (dr_swap_delta > DR_SWAP_RESPONSE_TIME) {
				usbpd_err(&pd->dev, "DR swap timedout(%lld), do not send ACCEPT\n",
								dr_swap_delta);
				break;
			}

			ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
			if (ret) {
				usbpd_set_state(pd, PE_SEND_SOFT_RESET);