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

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

usb: pd: Abort TX upon late RX



In general receiving a PD message should preempt a message
transmission in progress or about to be sent. Improve this
behavior by moving the check for any newly received messages
into pd_send_msg(). Also within the PD PHY driver, try to catch
scenarios in which an RX message arrives after pd_phy_write()
has been called but just before the TX register write operation
by checking the rx_msg_cnt counter to see if it changed since
the start of the function call.

Change-Id: I4084d18940b36df1f6eab8b0256ef30a81369884
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 30158a8e
Loading
Loading
Loading
Loading
+10 −9
Original line number Original line Diff line number Diff line
@@ -666,6 +666,7 @@ static inline void pd_reset_protocol(struct usbpd *pd)
static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
		size_t num_data, enum pd_sop_type sop)
		size_t num_data, enum pd_sop_type sop)
{
{
	unsigned long flags;
	int ret;
	int ret;
	u16 hdr;
	u16 hdr;


@@ -680,6 +681,15 @@ static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
		hdr = PD_MSG_HDR(msg_type, 0, 0, pd->tx_msgid[sop], num_data,
		hdr = PD_MSG_HDR(msg_type, 0, 0, pd->tx_msgid[sop], num_data,
				pd->spec_rev);
				pd->spec_rev);


	/* bail out and try again later if a message just arrived */
	spin_lock_irqsave(&pd->rx_lock, flags);
	if (!list_empty(&pd->rx_q)) {
		spin_unlock_irqrestore(&pd->rx_lock, flags);
		usbpd_dbg(&pd->dev, "Abort send due to pending RX\n");
		return -EBUSY;
	}
	spin_unlock_irqrestore(&pd->rx_lock, flags);

	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop);
	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop);
	if (ret) {
	if (ret) {
		if (pd->pd_connected)
		if (pd->pd_connected)
@@ -1501,20 +1511,11 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type)
static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type)
{
{
	int ret;
	int ret;
	unsigned long flags;


	/* only send one VDM at a time */
	/* only send one VDM at a time */
	if (pd->vdm_tx) {
	if (pd->vdm_tx) {
		u32 vdm_hdr = pd->vdm_tx->data[0];
		u32 vdm_hdr = pd->vdm_tx->data[0];


		/* bail out and try again later if a message just arrived */
		spin_lock_irqsave(&pd->rx_lock, flags);
		if (!list_empty(&pd->rx_q)) {
			spin_unlock_irqrestore(&pd->rx_lock, flags);
			return;
		}
		spin_unlock_irqrestore(&pd->rx_lock, flags);

		ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data,
		ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data,
				pd->vdm_tx->size, sop_type);
				pd->vdm_tx->size, sop_type);
		if (ret) {
		if (ret) {
+9 −1
Original line number Original line Diff line number Diff line
@@ -473,13 +473,16 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop)
	u8 val;
	u8 val;
	int ret;
	int ret;
	size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN;
	size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN;
	struct usb_pdphy *pdphy;
	struct usb_pdphy *pdphy = __pdphy;
	unsigned int msg_rx_cnt;


	if (!pdphy) {
	if (!pdphy) {
		pr_err("%s: pdphy not found\n", __func__);
		pr_err("%s: pdphy not found\n", __func__);
		return -ENODEV;
		return -ENODEV;
	}
	}


	msg_rx_cnt = pdphy->msg_rx_cnt;

	if (!pdphy->is_opened) {
	if (!pdphy->is_opened) {
		dev_dbg(pdphy->dev, "%s: pdphy disabled\n", __func__);
		dev_dbg(pdphy->dev, "%s: pdphy disabled\n", __func__);
		return -ENODEV;
		return -ENODEV;
@@ -537,6 +540,11 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop)
	else
	else
		val |= TX_CONTROL_RETRY_COUNT(3);
		val |= TX_CONTROL_RETRY_COUNT(3);


	if (msg_rx_cnt != pdphy->msg_rx_cnt) {
		dev_err(pdphy->dev, "%s: RX message arrived\n", __func__);
		return -EBUSY;
	}

	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
	if (ret)
	if (ret)
		return ret;
		return ret;