OSDN Git Service

usb: pdphy: Prevent sending when message is just received
authorJack Pham <jackp@codeaurora.org>
Wed, 7 Jun 2017 05:30:47 +0000 (22:30 -0700)
committerJack Pham <jackp@codeaurora.org>
Wed, 7 Jun 2017 05:50:28 +0000 (22:50 -0700)
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>
drivers/usb/pd/qpnp-pdphy.c

index 588af94..22c03ac 100644 (file)
@@ -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;