]> Pileus Git - ~andy/linux/blobdiff - drivers/staging/dwc2/hcd.c
Merge tag 'spi-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[~andy/linux] / drivers / staging / dwc2 / hcd.c
index da0d35cc33ce7dd3bc79245163b27c3f51fd8bbb..3cfd2d5152c92b001ce3fba0752665612a04d2c7 100644 (file)
@@ -537,10 +537,15 @@ static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg)
        int i;
 
        hsotg->flags.d32 = 0;
-
        hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active;
-       hsotg->non_periodic_channels = 0;
-       hsotg->periodic_channels = 0;
+
+       if (hsotg->core_params->uframe_sched > 0) {
+               hsotg->available_host_channels =
+                       hsotg->core_params->host_channels;
+       } else {
+               hsotg->non_periodic_channels = 0;
+               hsotg->periodic_channels = 0;
+       }
 
        /*
         * Put all channels in the free channel list and clean up channel
@@ -716,8 +721,7 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
  * @qh:    Transactions from the first QTD for this QH are selected and assigned
  *         to a free host channel
  */
-static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_qh *qh)
+static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
        struct dwc2_host_chan *chan;
        struct dwc2_hcd_urb *urb;
@@ -729,18 +733,18 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg,
 
        if (list_empty(&qh->qtd_list)) {
                dev_dbg(hsotg->dev, "No QTDs in QH list\n");
-               return;
+               return -ENOMEM;
        }
 
        if (list_empty(&hsotg->free_hc_list)) {
                dev_dbg(hsotg->dev, "No free channel to assign\n");
-               return;
+               return -ENOMEM;
        }
 
        chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan,
                                hc_list_entry);
 
-       /* Remove the host channel from the free list */
+       /* Remove host channel from free list */
        list_del_init(&chan->hc_list_entry);
 
        qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
@@ -780,6 +784,10 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg,
        chan->data_pid_start = qh->data_toggle;
        chan->multi_count = 1;
 
+       if (urb->actual_length > urb->length &&
+               !dwc2_hcd_is_pipe_in(&urb->pipe_info))
+               urb->actual_length = urb->length;
+
        if (hsotg->core_params->dma_enable > 0) {
                chan->xfer_dma = urb->dma + urb->actual_length;
 
@@ -817,7 +825,7 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg,
                                      &hsotg->free_hc_list);
                        qtd->in_process = 0;
                        qh->channel = NULL;
-                       return;
+                       return -ENOMEM;
                }
        } else {
                chan->align_buf = 0;
@@ -836,6 +844,8 @@ static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg,
 
        dwc2_hc_init(hsotg, chan);
        chan->qh = qh;
+
+       return 0;
 }
 
 /**
@@ -864,8 +874,14 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
        while (qh_ptr != &hsotg->periodic_sched_ready) {
                if (list_empty(&hsotg->free_hc_list))
                        break;
+               if (hsotg->core_params->uframe_sched > 0) {
+                       if (hsotg->available_host_channels <= 1)
+                               break;
+                       hsotg->available_host_channels--;
+               }
                qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
-               dwc2_assign_and_init_hc(hsotg, qh);
+               if (dwc2_assign_and_init_hc(hsotg, qh))
+                       break;
 
                /*
                 * Move the QH from the periodic ready schedule to the
@@ -884,13 +900,21 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
        num_channels = hsotg->core_params->host_channels;
        qh_ptr = hsotg->non_periodic_sched_inactive.next;
        while (qh_ptr != &hsotg->non_periodic_sched_inactive) {
-               if (hsotg->non_periodic_channels >= num_channels -
+               if (hsotg->core_params->uframe_sched <= 0 &&
+                   hsotg->non_periodic_channels >= num_channels -
                                                hsotg->periodic_channels)
                        break;
                if (list_empty(&hsotg->free_hc_list))
                        break;
                qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
-               dwc2_assign_and_init_hc(hsotg, qh);
+               if (hsotg->core_params->uframe_sched > 0) {
+                       if (hsotg->available_host_channels < 1)
+                               break;
+                       hsotg->available_host_channels--;
+               }
+
+               if (dwc2_assign_and_init_hc(hsotg, qh))
+                       break;
 
                /*
                 * Move the QH from the non-periodic inactive schedule to the
@@ -905,7 +929,8 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions(
                else
                        ret_val = DWC2_TRANSACTION_ALL;
 
-               hsotg->non_periodic_channels++;
+               if (hsotg->core_params->uframe_sched <= 0)
+                       hsotg->non_periodic_channels++;
        }
 
        return ret_val;
@@ -2848,6 +2873,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
                hsotg->hc_ptr_array[i] = channel;
        }
 
+       if (hsotg->core_params->uframe_sched > 0)
+               dwc2_hcd_init_usecs(hsotg);
+
        /* Initialize hsotg start work */
        INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);