usb: gadget: fix crash on USB cable disconnection
Crash was observed (9x15) when USB cable was
disconnected. Root cause was NULL pointer and
USB BAM reset due to USB PHY reset. On 9x15 no
reset on disconnect will be performed.
CRs-Fixed: 326999
Change-Id: I006afb8dcd225caf9280dd915f8af3edfaebff5a
Signed-off-by: Ofir Cohen <ofirc@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index ec2a71d..7259603 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -334,6 +334,7 @@
.phy_type = SNPS_28NM_INTEGRATED_PHY,
.pclk_src_name = "dfab_usb_hs_clk",
.vbus_power = msm_hsusb_vbus_power,
+ .disable_reset_on_disconnect = true,
};
static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 9605927..fb850b0 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -665,6 +665,27 @@
struct bam_ch_info *d = &port->data_ch;
u32 sps_params;
int ret;
+ unsigned long flags;
+
+ ret = usb_ep_enable(port->gr->in, port->gr->in_desc);
+ if (ret) {
+ pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
+ __func__, port->gr->in);
+ return;
+ }
+ port->gr->in->driver_data = port;
+
+ ret = usb_ep_enable(port->gr->out, port->gr->out_desc);
+ if (ret) {
+ pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
+ __func__, port->gr->out);
+ port->gr->in->driver_data = 0;
+ return;
+ }
+ port->gr->out->driver_data = port;
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = port->gr;
+ spin_unlock_irqrestore(&port->port_lock, flags);
ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
&d->dst_pipe_idx);
@@ -1047,37 +1068,39 @@
d = &port->data_ch;
- ret = usb_ep_enable(gr->in, gr->in_desc);
- if (ret) {
- pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
- __func__, gr->in);
- return ret;
- }
- gr->in->driver_data = port;
-
- ret = usb_ep_enable(gr->out, gr->out_desc);
- if (ret) {
- pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
- __func__, gr->out);
- gr->in->driver_data = 0;
- return ret;
- }
- gr->out->driver_data = port;
-
- spin_lock_irqsave(&port->port_lock, flags);
- port->port_usb = gr;
-
if (trans == USB_GADGET_XPORT_BAM) {
+ ret = usb_ep_enable(gr->in, gr->in_desc);
+ if (ret) {
+ pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
+ __func__, gr->in);
+ return ret;
+ }
+ gr->in->driver_data = port;
+
+ ret = usb_ep_enable(gr->out, gr->out_desc);
+ if (ret) {
+ pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
+ __func__, gr->out);
+ gr->in->driver_data = 0;
+ return ret;
+ }
+ gr->out->driver_data = port;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = gr;
+
d->to_host = 0;
d->to_modem = 0;
d->pending_with_bam = 0;
d->tohost_drp_cnt = 0;
d->tomodem_drp_cnt = 0;
+ spin_unlock_irqrestore(&port->port_lock, flags);
}
- spin_unlock_irqrestore(&port->port_lock, flags);
- if (trans == USB_GADGET_XPORT_BAM2BAM)
+ if (trans == USB_GADGET_XPORT_BAM2BAM) {
+ port->gr = gr;
d->connection_idx = connection_idx;
+ }
queue_work(gbam_wq, &port->connect_w);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index d756dd8..4932551 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -523,6 +523,18 @@
u32 val = 0;
u32 ulpi_val = 0;
+ /*
+ * USB PHY and Link reset also reset the USB BAM.
+ * Thus perform reset operation only once to avoid
+ * USB BAM reset on other cases e.g. USB cable disconnections.
+ */
+ if (pdata->disable_reset_on_disconnect) {
+ if (motg->reset_counter)
+ return 0;
+ else
+ motg->reset_counter++;
+ }
+
clk_enable(motg->clk);
ret = msm_otg_phy_reset(motg);
if (ret) {
@@ -2333,6 +2345,9 @@
goto free_motg;
}
+ /* initialize reset counter */
+ motg->reset_counter = 0;
+
/* Some targets don't support PHY clock. */
motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
if (IS_ERR(motg->phy_reset_clk))
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index eb2c543..409e697 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -159,6 +159,8 @@
* dfab_usb_hs_clk in case of 8660 and 8960.
* @pmic_id_irq: IRQ number assigned for PMIC USB ID line.
* @mhl_enable: indicates MHL connector or not.
+ * @disable_reset_on_disconnect: perform USB PHY and LINK reset
+ * on USB cable disconnection.
* @swfi_latency: miminum latency to allow swfi.
*/
struct msm_otg_platform_data {
@@ -173,6 +175,7 @@
const char *pclk_src_name;
int pmic_id_irq;
bool mhl_enable;
+ bool disable_reset_on_disconnect;
u32 swfi_latency;
};
@@ -263,6 +266,7 @@
#define PHY_RETENTIONED BIT(1)
#define PHY_OTG_COMP_DISABLED BIT(2)
struct pm_qos_request_list pm_qos_req_dma;
+ int reset_counter;
};
struct msm_hsic_host_platform_data {