These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / usb / dwc2 / hcd_intr.c
index 551ba87..bda0b21 100644 (file)
@@ -148,7 +148,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
                dwc2_hcd_queue_transactions(hsotg, tr_type);
 
        /* Clear interrupt */
-       writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
+       dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
 }
 
 /*
@@ -164,7 +164,7 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
        if (dbg_perio())
                dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
 
-       grxsts = readl(hsotg->regs + GRXSTSP);
+       grxsts = dwc2_readl(hsotg->regs + GRXSTSP);
        chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
        chan = hsotg->hc_ptr_array[chnum];
        if (!chan) {
@@ -247,11 +247,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
        dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
 
        /* Every time when port enables calculate HFIR.FrInterval */
-       hfir = readl(hsotg->regs + HFIR);
+       hfir = dwc2_readl(hsotg->regs + HFIR);
        hfir &= ~HFIR_FRINT_MASK;
        hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
                HFIR_FRINT_MASK;
-       writel(hfir, hsotg->regs + HFIR);
+       dwc2_writel(hfir, hsotg->regs + HFIR);
 
        /* Check if we need to adjust the PHY clock speed for low power */
        if (!params->host_support_fs_ls_low_power) {
@@ -260,7 +260,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                return;
        }
 
-       usbcfg = readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
        prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
 
        if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
@@ -268,11 +268,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
                        /* Set PHY low power clock select for FS/LS devices */
                        usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
-                       writel(usbcfg, hsotg->regs + GUSBCFG);
+                       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
                        do_reset = 1;
                }
 
-               hcfg = readl(hsotg->regs + HCFG);
+               hcfg = dwc2_readl(hsotg->regs + HCFG);
                fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
                              HCFG_FSLSPCLKSEL_SHIFT;
 
@@ -286,7 +286,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                                fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
                                hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
                                hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
-                               writel(hcfg, hsotg->regs + HCFG);
+                               dwc2_writel(hcfg, hsotg->regs + HCFG);
                                do_reset = 1;
                        }
                } else {
@@ -297,7 +297,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                                fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
                                hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
                                hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
-                               writel(hcfg, hsotg->regs + HCFG);
+                               dwc2_writel(hcfg, hsotg->regs + HCFG);
                                do_reset = 1;
                        }
                }
@@ -305,7 +305,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                /* Not low power */
                if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
                        usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
-                       writel(usbcfg, hsotg->regs + GUSBCFG);
+                       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
                        do_reset = 1;
                }
        }
@@ -332,7 +332,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
 
        dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
 
-       hprt0 = readl(hsotg->regs + HPRT0);
+       hprt0 = dwc2_readl(hsotg->regs + HPRT0);
        hprt0_modify = hprt0;
 
        /*
@@ -350,6 +350,9 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
                dev_vdbg(hsotg->dev,
                         "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
                         hprt0);
+               if (hsotg->lx_state != DWC2_L0)
+                       usb_hcd_resume_root_hub(hsotg->priv);
+
                hsotg->flags.b.port_connect_status_change = 1;
                hsotg->flags.b.port_connect_status = 1;
                hprt0_modify |= HPRT0_CONNDET;
@@ -385,7 +388,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
        }
 
        /* Clear Port Interrupts */
-       writel(hprt0_modify, hsotg->regs + HPRT0);
+       dwc2_writel(hprt0_modify, hsotg->regs + HPRT0);
 }
 
 /*
@@ -405,7 +408,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
 {
        u32 hctsiz, count, length;
 
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
 
        if (halt_status == DWC2_HC_XFER_COMPLETE) {
                if (chan->ep_is_in) {
@@ -463,10 +466,15 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
        }
 
        /* Non DWORD-aligned buffer case handling */
-       if (chan->align_buf && xfer_length && chan->ep_is_in) {
+       if (chan->align_buf && xfer_length) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size,
+                               chan->ep_is_in ?
+                               DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (chan->ep_is_in)
+                       memcpy(urb->buf + urb->actual_length,
+                                       chan->qh->dw_align_buf, xfer_length);
        }
 
        dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
@@ -483,7 +491,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
                urb->status = 0;
        }
 
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
        dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
                 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
        dev_vdbg(hsotg->dev, "  chan->xfer_len %d\n", chan->xfer_len);
@@ -506,7 +514,7 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
                               struct dwc2_host_chan *chan, int chnum,
                               struct dwc2_qtd *qtd)
 {
-       u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
        u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
 
        if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
@@ -552,13 +560,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
                                        chan, chnum, qtd, halt_status, NULL);
 
                /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
+               if (chan->align_buf && frame_desc->actual_length) {
                        dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
                                 __func__);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
+                       dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                                       chan->qh->dw_align_buf_size,
+                                       chan->ep_is_in ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       if (chan->ep_is_in)
+                               memcpy(urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset,
+                                       chan->qh->dw_align_buf,
+                                       frame_desc->actual_length);
                }
                break;
        case DWC2_HC_XFER_FRAME_OVERRUN:
@@ -581,13 +594,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
                                        chan, chnum, qtd, halt_status, NULL);
 
                /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
+               if (chan->align_buf && frame_desc->actual_length) {
                        dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
                                 __func__);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
+                       dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                                       chan->qh->dw_align_buf_size,
+                                       chan->ep_is_in ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       if (chan->ep_is_in)
+                               memcpy(urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset,
+                                       chan->qh->dw_align_buf,
+                                       frame_desc->actual_length);
                }
 
                /* Skip whole frame */
@@ -753,9 +771,9 @@ cleanup:
                }
        }
 
-       haintmsk = readl(hsotg->regs + HAINTMSK);
+       haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
        haintmsk &= ~(1 << chan->hc_num);
-       writel(haintmsk, hsotg->regs + HAINTMSK);
+       dwc2_writel(haintmsk, hsotg->regs + HAINTMSK);
 
        /* Try to queue more transfers now that there's a free channel */
        tr_type = dwc2_hcd_select_transactions(hsotg);
@@ -802,9 +820,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
                         * is enabled so that the non-periodic schedule will
                         * be processed
                         */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
                        gintmsk |= GINTSTS_NPTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
                } else {
                        dev_vdbg(hsotg->dev, "isoc/intr\n");
                        /*
@@ -821,9 +839,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
                         * enabled so that the periodic schedule will be
                         * processed
                         */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
                        gintmsk |= GINTSTS_PTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
                }
        }
 }
@@ -888,7 +906,7 @@ static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
                                        struct dwc2_qtd *qtd,
                                        enum dwc2_halt_status halt_status)
 {
-       u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
 
        qtd->error_count = 0;
 
@@ -923,6 +941,8 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
 
        if (chan->align_buf) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size, DMA_FROM_DEVICE);
                memcpy(qtd->urb->buf + frame_desc->offset +
                       qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
        }
@@ -1152,13 +1172,19 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
        /* Non DWORD-aligned buffer case handling */
        if (chan->align_buf && xfer_length && chan->ep_is_in) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size,
+                               chan->ep_is_in ?
+                               DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (chan->ep_is_in)
+                       memcpy(urb->buf + urb->actual_length,
+                                       chan->qh->dw_align_buf,
+                                       xfer_length);
        }
 
        urb->actual_length += xfer_length;
 
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
        dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
                 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
        dev_vdbg(hsotg->dev, "  chan->start_pkt_count %d\n",
@@ -1182,6 +1208,16 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
                             struct dwc2_host_chan *chan, int chnum,
                             struct dwc2_qtd *qtd)
 {
+       if (!qtd) {
+               dev_dbg(hsotg->dev, "%s: qtd is NULL\n", __func__);
+               return;
+       }
+
+       if (!qtd->urb) {
+               dev_dbg(hsotg->dev, "%s: qtd->urb is NULL\n", __func__);
+               return;
+       }
+
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
                         chnum);
@@ -1469,10 +1505,10 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
 
        dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
 
-       hcchar = readl(hsotg->regs + HCCHAR(chnum));
-       hcsplt = readl(hsotg->regs + HCSPLT(chnum));
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-       hc_dma = readl(hsotg->regs + HCDMA(chnum));
+       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
+       hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
+       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       hc_dma = dwc2_readl(hsotg->regs + HCDMA(chnum));
 
        dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
        dev_err(hsotg->dev, "  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
@@ -1685,10 +1721,10 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
                 * This code is here only as a check. This condition should
                 * never happen. Ignore the halt if it does occur.
                 */
-               hcchar = readl(hsotg->regs + HCCHAR(chnum));
-               hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-               hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
-               hcsplt = readl(hsotg->regs + HCSPLT(chnum));
+               hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
+               hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+               hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
+               hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
                dev_dbg(hsotg->dev,
                        "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
                         __func__);
@@ -1712,7 +1748,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
         * when the halt interrupt occurs. Halt the channel again if it does
         * occur.
         */
-       hcchar = readl(hsotg->regs + HCCHAR(chnum));
+       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
        if (hcchar & HCCHAR_CHDIS) {
                dev_warn(hsotg->dev,
                         "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
@@ -1772,7 +1808,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
                return;
        }
 
-       hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+       hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
 
        if (chan->hcint & HCINTMSK_XFERCOMPL) {
                /*
@@ -1867,7 +1903,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
                                dev_err(hsotg->dev,
                                        "hcint 0x%08x, intsts 0x%08x\n",
                                        chan->hcint,
-                                       readl(hsotg->regs + GINTSTS));
+                                       dwc2_readl(hsotg->regs + GINTSTS));
                                goto error;
                        }
                }
@@ -1913,6 +1949,24 @@ static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
        }
 }
 
+/*
+ * Check if the given qtd is still the top of the list (and thus valid).
+ *
+ * If dwc2_hcd_qtd_unlink_and_free() has been called since we grabbed
+ * the qtd from the top of the list, this will return false (otherwise true).
+ */
+static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh)
+{
+       struct dwc2_qtd *cur_head;
+
+       if (qh == NULL)
+               return false;
+
+       cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd,
+                                   qtd_list_entry);
+       return (cur_head == qtd);
+}
+
 /* Handles interrupt for a specific Host Channel */
 static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
 {
@@ -1922,11 +1976,11 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
 
        chan = hsotg->hc_ptr_array[chnum];
 
-       hcint = readl(hsotg->regs + HCINT(chnum));
-       hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+       hcint = dwc2_readl(hsotg->regs + HCINT(chnum));
+       hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
        if (!chan) {
                dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
-               writel(hcint, hsotg->regs + HCINT(chnum));
+               dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
                return;
        }
 
@@ -1938,7 +1992,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
                         hcint, hcintmsk, hcint & hcintmsk);
        }
 
-       writel(hcint, hsotg->regs + HCINT(chnum));
+       dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
        chan->hcint = hcint;
        hcint &= hcintmsk;
 
@@ -1995,27 +2049,59 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
                 */
                hcint &= ~HCINTMSK_NYET;
        }
-       if (hcint & HCINTMSK_CHHLTD)
+
+       if (hcint & HCINTMSK_CHHLTD) {
                dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_AHBERR)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_AHBERR) {
                dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_STALL)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_STALL) {
                dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_NAK)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_NAK) {
                dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_ACK)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_ACK) {
                dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_NYET)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_NYET) {
                dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_XACTERR)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_XACTERR) {
                dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_BBLERR)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_BBLERR) {
                dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_FRMOVRUN)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_FRMOVRUN) {
                dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_DATATGLERR)
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
+       if (hcint & HCINTMSK_DATATGLERR) {
                dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
+               if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
+                       goto exit;
+       }
 
+exit:
        chan->hcint = 0;
 }
 
@@ -2030,7 +2116,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
        u32 haint;
        int i;
 
-       haint = readl(hsotg->regs + HAINT);
+       haint = dwc2_readl(hsotg->regs + HAINT);
        if (dbg_perio()) {
                dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
@@ -2098,8 +2184,8 @@ irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
                                 "DWC OTG HCD Finished Servicing Interrupts\n");
                        dev_vdbg(hsotg->dev,
                                 "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
-                                readl(hsotg->regs + GINTSTS),
-                                readl(hsotg->regs + GINTMSK));
+                                dwc2_readl(hsotg->regs + GINTSTS),
+                                dwc2_readl(hsotg->regs + GINTMSK));
                }
        }