summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Pham <jackp@codeaurora.org>2017-06-06 22:30:47 -0700
committerJack Pham <jackp@codeaurora.org>2017-06-06 22:50:28 -0700
commit71c2e3fc4ffa5aa629f3afd9d971b2e1f521255f (patch)
tree3f97dad65292c0fc78c769edbdde61efc87bb2e4
parent00adcfcbad43e8f68bed8c3f3df63b58f978137b (diff)
usb: pdphy: Prevent sending when message is just received
Prevent pd_phy_write() from sending a TX message if an RX message IRQ is being handled, or if the RX_TOKEN is set (indicating a message has just arrived) by returning -EBUSY to let the upper layer gracefully abort. This helps in cases (such as compliance testing) in which VDM messages are received very quickly after one another and the protocol layer needs to first handle the incoming message. Change-Id: I3e26d7ff062ff7f51b6c66ab8d078b05749f808a Signed-off-by: Jack Pham <jackp@codeaurora.org>
-rw-r--r--drivers/usb/pd/qpnp-pdphy.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 588af94db6cd..22c03ace78e7 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -108,6 +108,7 @@ struct usb_pdphy {
int tx_status;
u8 frame_filter_val;
bool in_test_data_mode;
+ bool rx_busy;
enum data_role data_role;
enum power_role power_role;
@@ -492,6 +493,12 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
return -EINVAL;
}
+ ret = pdphy_reg_read(pdphy, &val, USB_PDPHY_RX_ACKNOWLEDGE, 1);
+ if (ret || val || pdphy->rx_busy) {
+ dev_err(pdphy->dev, "%s: RX message pending\n", __func__);
+ return -EBUSY;
+ }
+
pdphy->tx_status = -EINPROGRESS;
/* write 2 byte SOP message header */
@@ -664,6 +671,15 @@ static int pd_phy_bist_mode(u8 bist_mode)
BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE);
}
+static irqreturn_t pdphy_msg_rx_irq(int irq, void *data)
+{
+ struct usb_pdphy *pdphy = data;
+
+ pdphy->rx_busy = true;
+
+ return IRQ_WAKE_THREAD;
+}
+
static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
{
u8 size, rx_status, frame_type;
@@ -720,6 +736,7 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
false);
pdphy->rx_bytes += size + 1;
done:
+ pdphy->rx_busy = false;
return IRQ_HANDLED;
}
@@ -805,7 +822,7 @@ static int pdphy_probe(struct platform_device *pdev)
return ret;
ret = pdphy_request_irq(pdphy, pdev->dev.of_node,
- &pdphy->msg_rx_irq, "msg-rx", NULL,
+ &pdphy->msg_rx_irq, "msg-rx", pdphy_msg_rx_irq,
pdphy_msg_rx_irq_thread, (IRQF_TRIGGER_RISING | IRQF_ONESHOT));
if (ret < 0)
return ret;