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

Commit 9f8d1486 authored by Jack Pham's avatar Jack Pham
Browse files

usb: pd: ensure source hard reset is handled timely



When in source mode if a hard reset is received just before or
while usbpd_sm() is in the middle of trying to send an outgoing
message, the signal handling would get delayed due waiting for
the PD PHY to complete retrying and failing both the message as
well as the subsequent Soft_Reset message. Instead, treat the
incoming hard reset with priority try to bail out of further
attempts to send a message so that we can immeidately re-queue and
process the hard reset on the next usbpd_sm() invocation.

In case the TX attempt still manages to win the race, this will
cause delay that affects our tPSHardReset (25-35ms) required time
resulting in VBUS getting turned off too late. Handle this by
keeping track of when the hard reset signal arrived so that
we can schedule SRC_TRANSITION_TO_DEFAULT within this window.

Also promote the error message when a hard reset is received
from KERN_DEBUG to KERN_ERR, as this is abnormal enough
to deserve printing to the kernel log with higher priority.

Change-Id: Ie503f7b776022067ec3a4788d5229ec508b9c55f
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent f83e3150
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -368,6 +368,7 @@ struct usbpd {

	enum usbpd_state	current_state;
	bool			hard_reset_recvd;
	ktime_t			hard_reset_recvd_time;
	struct list_head	rx_q;
	spinlock_t		rx_lock;
	struct rx_msg		*rx_ext_msg;
@@ -556,6 +557,9 @@ static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
	int ret;
	u16 hdr;

	if (pd->hard_reset_recvd)
		return -EBUSY;

	hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr,
			pd->tx_msgid, num_data, pd->spec_rev);

@@ -747,11 +751,13 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type sig)
		return;
	}

	usbpd_dbg(&pd->dev, "hard reset received\n");
	pd->hard_reset_recvd = true;
	pd->hard_reset_recvd_time = ktime_get();

	usbpd_err(&pd->dev, "hard reset received\n");

	/* Force CC logic to source/sink to keep Rp/Rd unchanged */
	set_power_role(pd, pd->current_pr);
	pd->hard_reset_recvd = true;
	power_supply_set_property(pd->usb_psy,
			POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);

@@ -1006,6 +1012,9 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
	unsigned long flags;
	int ret;

	if (pd->hard_reset_recvd) /* let usbpd_sm handle it */
		return;

	usbpd_dbg(&pd->dev, "%s -> %s\n",
			usbpd_state_strings[pd->current_state],
			usbpd_state_strings[next_state]);
@@ -1977,8 +1986,13 @@ static void usbpd_sm(struct work_struct *w)
		if (pd->current_pr == PR_SINK) {
			usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT);
		} else {
			s64 delta = ktime_ms_delta(ktime_get(),
					pd->hard_reset_recvd_time);
			pd->current_state = PE_SRC_TRANSITION_TO_DEFAULT;
			kick_sm(pd, PS_HARD_RESET_TIME);
			if (delta >= PS_HARD_RESET_TIME)
				kick_sm(pd, 0);
			else
				kick_sm(pd, PS_HARD_RESET_TIME - (int)delta);
		}

		goto sm_done;
+8 −0
Original line number Diff line number Diff line
@@ -582,6 +582,10 @@ static irqreturn_t pdphy_msg_tx_irq(int irq, void *data)
{
	struct usb_pdphy *pdphy = data;

	/* TX already aborted by received signal */
	if (pdphy->tx_status != -EINPROGRESS)
		return IRQ_HANDLED;

	if (irq == pdphy->msg_tx_irq) {
		pdphy->msg_tx_cnt++;
		pdphy->tx_status = 0;
@@ -635,6 +639,10 @@ static irqreturn_t pdphy_sig_rx_irq_thread(int irq, void *data)
	if (pdphy->signal_cb)
		pdphy->signal_cb(pdphy->usbpd, frame_type);

	if (pdphy->tx_status == -EINPROGRESS) {
		pdphy->tx_status = -EBUSY;
		wake_up(&pdphy->tx_waitq);
	}
done:
	return IRQ_HANDLED;
}