usb: dwc_otg: fix some issues of dwc_otg_310
authorlyz <lyz@rock-chips.com>
Thu, 15 Jan 2015 05:13:03 +0000 (13:13 +0800)
committerlyz <lyz@rock-chips.com>
Thu, 15 Jan 2015 05:29:39 +0000 (13:29 +0800)
1.disable host interrupts when id changed so that no more host
  interrupt will happen after otg disconnect
2.hold hcd->lock in hcd_reinit function to protect qtd list
3.recheck USB_STATUS_ID in vbus detect thread make sure it indeed
  in device mode
4.fix some null pointer dereference
5.otg disconnect threshold set to 575mv in case of disconnect
  interrupt lose

drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c
drivers/usb/dwc_otg_310/dwc_otg_hcd.c
drivers/usb/dwc_otg_310/dwc_otg_hcd_linux.c
drivers/usb/dwc_otg_310/dwc_otg_hcd_queue.c
drivers/usb/dwc_otg_310/dwc_otg_pcd_linux.c
drivers/usb/dwc_otg_310/usbdev_rk3126.c

index 78bf20d2a1af52da0d857505e28ca5d2b7f7f716..9e25e90bd47047220c48a4fb92619672f36343ea 100755 (executable)
@@ -389,6 +389,7 @@ int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
        gintmsk_data_t gintmsk = {.d32 = 0 };
        gintsts_data_t gintsts = {.d32 = 0 };
 
+       dwc_otg_disable_host_interrupts(core_if);
        if (core_if->usb_mode != USB_MODE_NORMAL)
                goto out;
 
index 1ad27556227caf31b4669e36be9979609617518c..9bde3ba4da05c4b56c3547d47ddabcde50f042a1 100755 (executable)
@@ -179,6 +179,8 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t *hcd, dwc_list_link_t *qh_list)
                                hcd->fops->complete(hcd, qtd->urb->priv,
                                                    qtd->urb, -DWC_E_SHUTDOWN);
                                dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+                       } else {
+                               return;
                        }
 
                }
@@ -953,6 +955,7 @@ static void dwc_otg_hcd_reinit(dwc_otg_hcd_t *hcd)
        int i;
        dwc_hc_t *channel;
        dwc_hc_t *channel_tmp;
+       dwc_irqflags_t flags;
 
        hcd->flags.d32 = 0;
 
@@ -960,6 +963,7 @@ static void dwc_otg_hcd_reinit(dwc_otg_hcd_t *hcd)
        hcd->non_periodic_channels = 0;
        hcd->periodic_channels = 0;
 
+       DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
        /*
         * Put all channels in the free channel list and clean up channel
         * states.
@@ -976,7 +980,7 @@ static void dwc_otg_hcd_reinit(dwc_otg_hcd_t *hcd)
                                        hc_list_entry);
                dwc_otg_hc_cleanup(hcd->core_if, channel);
        }
-
+       DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
        /* Initialize the DWC core for host mode operation. */
        dwc_otg_core_host_init(hcd->core_if);
 
@@ -1334,6 +1338,8 @@ static int queue_transaction(dwc_otg_hcd_t *hcd,
                                hc->qh->ping_state = 0;
                        }
                } else if (!hc->xfer_started) {
+                       if (!hc || !(hc->qh))
+                               return -ENODEV;
                        dwc_otg_hc_start_transfer(hcd->core_if, hc);
                        hc->qh->ping_state = 0;
                }
index b726c90baf3c238d7e9ff36e77938979f3684012..3a48dc3e52a32bda01f1e2c645260ed07104040d 100755 (executable)
@@ -239,6 +239,8 @@ static int _complete(dwc_otg_hcd_t *hcd, void *urb_handle,
                     dwc_otg_hcd_urb_t *dwc_otg_urb, int32_t status)
 {
        struct urb *urb = (struct urb *)urb_handle;
+       if (!urb)
+               return 0;
 #ifdef DEBUG
        if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
                DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
index faa7327943e647a4e218d484987e098ba40d663c..353693f176436d4b06b05910067fa5ef2c066b2f 100755 (executable)
@@ -58,8 +58,7 @@ void dwc_otg_hcd_qh_free(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
        /* Free each QTD in the QTD list */
        DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
        DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
-               DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
-               dwc_otg_hcd_qtd_free(qtd);
+               dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
        }
 
        if (hcd->core_if->dma_desc_enable) {
index d22768ce21ee99db71b0afd0eb1cafbe41cc0161..d234c06bb53f6fe10fe5f6727881c90636b651eb 100755 (executable)
@@ -1605,7 +1605,8 @@ static void dwc_otg_pcd_check_vbus_work(struct work_struct *work)
        struct dwc_otg_device *otg_dev = _pcd->otg_dev;
        struct dwc_otg_platform_data *pldata = otg_dev->pldata;
 
-       if (pldata->get_status(USB_STATUS_BVABLID)) {
+       if (pldata->get_status(USB_STATUS_BVABLID) &&
+           pldata->get_status(USB_STATUS_ID)) {
                /* if usb not connect before ,then start connect */
                if (_pcd->vbus_status == USB_BC_TYPE_DISCNT) {
                        printk("***************vbus detect*****************\n");
index eff95d8a83af7c994e538ef52cd56fde45759554..d71e8c3f7134605ab60aaeb461e54d537604421a 100755 (executable)
@@ -8,10 +8,10 @@ static void usb20otg_hw_init(void)
 {
        /* Turn off differential receiver in suspend mode */
        writel(UOC_HIWORD_UPDATE(0, 1, 2),
-                  RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON6);
+              RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON6);
        /* Set disconnect detection trigger point to 600mv */
-       writel(UOC_HIWORD_UPDATE(1, 0xf, 11),
-                  RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON7);
+       writel(UOC_HIWORD_UPDATE(0, 0xf, 11),
+              RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON7);
        /* other haredware init,include:
         * DRV_VBUS GPIO init */
        if (gpio_is_valid(control_usb->otg_gpios->gpio)) {