These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / usb / dwc2 / hcd_queue.c
index bb97838..7d8d06c 100644 (file)
@@ -106,6 +106,9 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                                USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
                                qh->ep_type == USB_ENDPOINT_XFER_ISOC,
                                bytecount));
+
+               /* Ensure frame_number corresponds to the reality */
+               hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
                /* Start in a slightly future (micro)frame */
                qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
                                                     SCHEDULE_SLOP);
@@ -115,7 +118,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                if (qh->ep_type == USB_ENDPOINT_XFER_INT)
                        qh->interval = 8;
 #endif
-               hprt = readl(hsotg->regs + HPRT0);
+               hprt = dwc2_readl(hsotg->regs + HPRT0);
                prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
                if (prtspd == HPRT0_SPD_HIGH_SPEED &&
                    (dev_speed == USB_SPEED_LOW ||
@@ -191,7 +194,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
  *
  * Return: Pointer to the newly allocated QH, or NULL on error
  */
-static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
                                          struct dwc2_hcd_urb *urb,
                                          gfp_t mem_flags)
 {
@@ -229,11 +232,13 @@ static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
  */
 void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
-       if (hsotg->core_params->dma_desc_enable > 0)
+       if (hsotg->core_params->dma_desc_enable > 0) {
                dwc2_hcd_qh_free_ddma(hsotg, qh);
-       else if (qh->dw_align_buf)
-               dma_free_coherent(hsotg->dev, qh->dw_align_buf_size,
-                                 qh->dw_align_buf, qh->dw_align_buf_dma);
+       } else {
+               /* kfree(NULL) is safe */
+               kfree(qh->dw_align_buf);
+               qh->dw_align_buf_dma = (dma_addr_t)0;
+       }
        kfree(qh);
 }
 
@@ -581,6 +586,14 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
                /* QH already in a schedule */
                return 0;
 
+       if (!dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number) &&
+                       !hsotg->frame_number) {
+               dev_dbg(hsotg->dev,
+                               "reset frame number counter\n");
+               qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
+                               SCHEDULE_SLOP);
+       }
+
        /* Add the new QH to the appropriate schedule */
        if (dwc2_qh_is_non_per(qh)) {
                /* Always start in inactive schedule */
@@ -593,9 +606,9 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
        if (status)
                return status;
        if (!hsotg->periodic_qh_count) {
-               intr_mask = readl(hsotg->regs + GINTMSK);
+               intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
                intr_mask |= GINTSTS_SOF;
-               writel(intr_mask, hsotg->regs + GINTMSK);
+               dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
        }
        hsotg->periodic_qh_count++;
 
@@ -630,9 +643,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
        dwc2_deschedule_periodic(hsotg, qh);
        hsotg->periodic_qh_count--;
        if (!hsotg->periodic_qh_count) {
-               intr_mask = readl(hsotg->regs + GINTMSK);
+               intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
                intr_mask &= ~GINTSTS_SOF;
-               writel(intr_mask, hsotg->regs + GINTMSK);
+               dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
        }
 }
 
@@ -761,67 +774,36 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
 
 /**
  * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
+ *                     Caller must hold driver lock.
  *
  * @hsotg:        The DWC HCD structure
  * @qtd:          The QTD to add
- * @qh:           Out parameter to return queue head
- * @atomic_alloc: Flag to do atomic alloc if needed
+ * @qh:           Queue head to add qtd to
  *
  * Return: 0 if successful, negative error code otherwise
  *
- * Finds the correct QH to place the QTD into. If it does not find a QH, it
- * will create a new QH. If the QH to which the QTD is added is not currently
- * scheduled, it is placed into the proper schedule based on its EP type.
+ * If the QH to which the QTD is added is not currently scheduled, it is placed
+ * into the proper schedule based on its EP type.
  */
 int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                    struct dwc2_qh **qh, gfp_t mem_flags)
+                    struct dwc2_qh *qh)
 {
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       unsigned long flags;
-       int allocated = 0;
        int retval;
 
-       /*
-        * Get the QH which holds the QTD-list to insert to. Create QH if it
-        * doesn't exist.
-        */
-       if (*qh == NULL) {
-               *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
-               if (*qh == NULL)
-                       return -ENOMEM;
-               allocated = 1;
+       if (unlikely(!qh)) {
+               dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
+               retval = -EINVAL;
+               goto fail;
        }
 
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       retval = dwc2_hcd_qh_add(hsotg, *qh);
+       retval = dwc2_hcd_qh_add(hsotg, qh);
        if (retval)
                goto fail;
 
-       qtd->qh = *qh;
-       list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
+       qtd->qh = qh;
+       list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
 
        return 0;
-
 fail:
-       if (allocated) {
-               struct dwc2_qtd *qtd2, *qtd2_tmp;
-               struct dwc2_qh *qh_tmp = *qh;
-
-               *qh = NULL;
-               dwc2_hcd_qh_unlink(hsotg, qh_tmp);
-
-               /* Free each QTD in the QH's QTD list */
-               list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
-                                        qtd_list_entry)
-                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
-
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               dwc2_hcd_qh_free(hsotg, qh_tmp);
-       } else {
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-       }
-
        return retval;
 }