usb: dwc_otg: fix bugs
authorlyz <lyz@rock-chips.com>
Fri, 10 Apr 2015 07:58:49 +0000 (15:58 +0800)
committerlyz <lyz@rock-chips.com>
Fri, 10 Apr 2015 08:30:56 +0000 (16:30 +0800)
1.Cancel usb vbus detect work in driver shutdown rountine
2.Check empty list
3.Disable usb interrupt before usb mode change

TEST:

1.reboot test
2.while true; do
    echo 1 > force_usb_mode;busybox sleep 5;
    echo 2 > force_usb_mode;busybox sleep 5;
  done

Signed-off-by: lyz <lyz@rock-chips.com>
drivers/usb/dwc_otg_310/dwc_otg_driver.c
drivers/usb/dwc_otg_310/dwc_otg_hcd.c
drivers/usb/dwc_otg_310/dwc_otg_hcd_intr.c

index 3aa41733671f000a950ee3df0b60bd9889c3ad51..4e064c6ac1a8660eaf966f2964dae5f13f017e84 100755 (executable)
@@ -1158,18 +1158,16 @@ static void dwc_otg_driver_shutdown(struct platform_device *_dev)
        dwc_otg_core_if_t *core_if = otg_dev->core_if;
        struct dwc_otg_platform_data *pldata = otg_dev->pldata;
        dctl_data_t dctl = {.d32 = 0 };
+       dwc_otg_pcd_t *pcd = core_if->otg_dev->pcd;
 
        DWC_PRINTF("%s: disconnect USB %s mode\n", __func__,
                   dwc_otg_is_host_mode(core_if) ? "host" : "device");
 
-       if (pldata->dwc_otg_uart_mode != NULL)
-               pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);
-       if (pldata->phy_suspend != NULL)
-               pldata->phy_suspend(pldata, USB_PHY_ENABLED);
        if (dwc_otg_is_host_mode(core_if)) {
                if (core_if->hcd_cb && core_if->hcd_cb->stop)
                        core_if->hcd_cb->stop(core_if->hcd_cb_p);
        } else {
+               cancel_delayed_work_sync(&pcd->check_vbus_work);
                /* soft disconnect */
                dctl.d32 =
                    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
@@ -1180,6 +1178,11 @@ static void dwc_otg_driver_shutdown(struct platform_device *_dev)
        /* Clear any pending interrupts */
        DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
 
+       if (pldata->dwc_otg_uart_mode != NULL)
+               pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);
+       if (pldata->phy_suspend != NULL)
+               pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+
 }
 
 /**
index ff123682de68a389126ab9975d06096efca84e36..4f2e7ac8a1b7d7128ba67a79f994ba50ad0feeeb 100755 (executable)
@@ -174,6 +174,8 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t *hcd, dwc_list_link_t *qh_list)
                qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
                DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
                                         &qh->qtd_list, qtd_list_entry) {
+                       if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list))
+                               return;
                        qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
                        if (qtd->urb != NULL) {
                                hcd->fops->complete(hcd, qtd->urb->priv,
@@ -478,6 +480,9 @@ void dwc_otg_hcd_stop(dwc_otg_hcd_t *hcd)
        pldata = hcd->core_if->otg_dev->pldata;
        DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
 
+       /* Turn off all host-specific interrupts. */
+       dwc_otg_disable_host_interrupts(hcd->core_if);
+
        /*
         * The root hub should be disconnected before this function is called.
         * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
@@ -493,9 +498,6 @@ void dwc_otg_hcd_stop(dwc_otg_hcd_t *hcd)
        hcd->flags.b.port_connect_status_change = 1;
        hcd->flags.b.port_connect_status = 0;
 
-       /* Turn off all host-specific interrupts. */
-       dwc_otg_disable_host_interrupts(hcd->core_if);
-
        /* Turn off the vbus power */
        DWC_PRINTF("PortPower off\n");
        hprt0.b.prtpwr = 0;
@@ -1349,7 +1351,8 @@ static int queue_transaction(dwc_otg_hcd_t *hcd,
                             dwc_hc_t *hc, uint16_t fifo_dwords_avail)
 {
        int retval;
-
+       if (!hc || !(hc->qh))
+               return -ENODEV;
        if (hcd->core_if->dma_enable) {
                if (hcd->core_if->dma_desc_enable) {
                        if (!hc->xfer_started
index a7bbaaeeeacd77c232ceb760c2283bebf39e5be4..22a118efeae7e12146983c0eed9ac64871674d91 100755 (executable)
@@ -2101,6 +2101,12 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t *dwc_otg_hcd, uint32_t num)
 
        hc = dwc_otg_hcd->hc_ptr_array[num];
        hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
+       if (DWC_CIRCLEQ_EMPTY(&hc->qh->qtd_list)) {
+               /* All transfer had been killed, clear panding interrupts */
+               hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
+               DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32);
+               return retval;
+       }
        qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
 
        hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);