LCOV - code coverage report
Current view: top level - drivers/usb/host/dwc_otg - dwc_otg_hcd_queue.c (source / functions) Hit Total Coverage
Test: Real Lines: 226 304 74.3 %
Date: 2020-10-17 15:46:16 Functions: 3 18 16.7 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* ==========================================================================
       2                 :            :  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
       3                 :            :  * $Revision: #44 $
       4                 :            :  * $Date: 2011/10/26 $
       5                 :            :  * $Change: 1873028 $
       6                 :            :  *
       7                 :            :  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
       8                 :            :  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
       9                 :            :  * otherwise expressly agreed to in writing between Synopsys and you.
      10                 :            :  *
      11                 :            :  * The Software IS NOT an item of Licensed Software or Licensed Product under
      12                 :            :  * any End User Software License Agreement or Agreement for Licensed Product
      13                 :            :  * with Synopsys or any supplement thereto. You are permitted to use and
      14                 :            :  * redistribute this Software in source and binary forms, with or without
      15                 :            :  * modification, provided that redistributions of source code must retain this
      16                 :            :  * notice. You may not view, use, disclose, copy or distribute this file or
      17                 :            :  * any information contained herein except pursuant to this license grant from
      18                 :            :  * Synopsys. If you do not agree with this notice, including the disclaimer
      19                 :            :  * below, then you are not authorized to use the Software.
      20                 :            :  *
      21                 :            :  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
      22                 :            :  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23                 :            :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24                 :            :  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
      25                 :            :  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      26                 :            :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      27                 :            :  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
      28                 :            :  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29                 :            :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30                 :            :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
      31                 :            :  * DAMAGE.
      32                 :            :  * ========================================================================== */
      33                 :            : #ifndef DWC_DEVICE_ONLY
      34                 :            : 
      35                 :            : /**
      36                 :            :  * @file
      37                 :            :  *
      38                 :            :  * This file contains the functions to manage Queue Heads and Queue
      39                 :            :  * Transfer Descriptors.
      40                 :            :  */
      41                 :            : 
      42                 :            : #include "dwc_otg_hcd.h"
      43                 :            : #include "dwc_otg_regs.h"
      44                 :            : 
      45                 :            : extern bool microframe_schedule;
      46                 :            : extern unsigned short int_ep_interval_min;
      47                 :            : 
      48                 :            : /**
      49                 :            :  * Free each QTD in the QH's QTD-list then free the QH.  QH should already be
      50                 :            :  * removed from a list.  QTD list should already be empty if called from URB
      51                 :            :  * Dequeue.
      52                 :            :  *
      53                 :            :  * @param hcd HCD instance.
      54                 :            :  * @param qh The QH to free.
      55                 :            :  */
      56                 :          3 : void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
      57                 :            : {
      58                 :            :         dwc_otg_qtd_t *qtd, *qtd_tmp;
      59                 :            :         dwc_irqflags_t flags;
      60                 :            :         uint32_t buf_size = 0;
      61                 :            :         uint8_t *align_buf_virt = NULL;
      62                 :            :         dwc_dma_t align_buf_dma;
      63                 :            :         struct device *dev = dwc_otg_hcd_to_dev(hcd);
      64                 :            : 
      65                 :            :         /* Free each QTD in the QTD list */
      66                 :          3 :         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
      67                 :          3 :         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
      68                 :          0 :                 DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
      69                 :            :                 dwc_otg_hcd_qtd_free(qtd);
      70                 :            :         }
      71                 :            : 
      72                 :          3 :         if (hcd->core_if->dma_desc_enable) {
      73                 :          0 :                 dwc_otg_hcd_qh_free_ddma(hcd, qh);
      74                 :          3 :         } else if (qh->dw_align_buf) {
      75                 :          0 :                 if (qh->ep_type == UE_ISOCHRONOUS) {
      76                 :            :                         buf_size = 4096;
      77                 :            :                 } else {
      78                 :          0 :                         buf_size = hcd->core_if->core_params->max_transfer_size;
      79                 :            :                 }
      80                 :            :                 align_buf_virt = qh->dw_align_buf;
      81                 :          0 :                 align_buf_dma = qh->dw_align_buf_dma;
      82                 :            :         }
      83                 :            : 
      84                 :          3 :         DWC_FREE(qh);
      85                 :          3 :         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
      86                 :          3 :         if (align_buf_virt)
      87                 :          0 :                 DWC_DMA_FREE(dev, buf_size, align_buf_virt, align_buf_dma);
      88                 :          3 :         return;
      89                 :            : }
      90                 :            : 
      91                 :            : #define BitStuffTime(bytecount)  ((8 * 7* bytecount) / 6)
      92                 :            : #define HS_HOST_DELAY           5       /* nanoseconds */
      93                 :            : #define FS_LS_HOST_DELAY        1000    /* nanoseconds */
      94                 :            : #define HUB_LS_SETUP            333     /* nanoseconds */
      95                 :            : #define NS_TO_US(ns)            ((ns + 500) / 1000)
      96                 :            :                                 /* convert & round nanoseconds to microseconds */
      97                 :            : 
      98                 :          3 : static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
      99                 :            : {
     100                 :            :         unsigned long retval;
     101                 :            : 
     102                 :          3 :         switch (speed) {
     103                 :            :         case USB_SPEED_HIGH:
     104                 :          2 :                 if (is_isoc) {
     105                 :          0 :                         retval =
     106                 :          0 :                             ((38 * 8 * 2083) +
     107                 :          0 :                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
     108                 :            :                             HS_HOST_DELAY;
     109                 :            :                 } else {
     110                 :          2 :                         retval =
     111                 :          2 :                             ((55 * 8 * 2083) +
     112                 :          2 :                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
     113                 :            :                             HS_HOST_DELAY;
     114                 :            :                 }
     115                 :            :                 break;
     116                 :            :         case USB_SPEED_FULL:
     117                 :          1 :                 if (is_isoc) {
     118                 :          0 :                         retval =
     119                 :          0 :                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
     120                 :          0 :                         if (is_in) {
     121                 :          0 :                                 retval = 7268 + FS_LS_HOST_DELAY + retval;
     122                 :            :                         } else {
     123                 :          0 :                                 retval = 6265 + FS_LS_HOST_DELAY + retval;
     124                 :            :                         }
     125                 :            :                 } else {
     126                 :          1 :                         retval =
     127                 :          1 :                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
     128                 :          1 :                         retval = 9107 + FS_LS_HOST_DELAY + retval;
     129                 :            :                 }
     130                 :            :                 break;
     131                 :            :         case USB_SPEED_LOW:
     132                 :          0 :                 if (is_in) {
     133                 :          0 :                         retval =
     134                 :          0 :                             (67667 * (31 + 10 * BitStuffTime(bytecount))) /
     135                 :            :                             1000;
     136                 :          0 :                         retval =
     137                 :            :                             64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
     138                 :            :                             retval;
     139                 :            :                 } else {
     140                 :          0 :                         retval =
     141                 :          0 :                             (66700 * (31 + 10 * BitStuffTime(bytecount))) /
     142                 :            :                             1000;
     143                 :          0 :                         retval =
     144                 :            :                             64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
     145                 :            :                             retval;
     146                 :            :                 }
     147                 :            :                 break;
     148                 :            :         default:
     149                 :          0 :                 DWC_WARN("Unknown device speed\n");
     150                 :            :                 retval = -1;
     151                 :            :         }
     152                 :            : 
     153                 :          3 :         return NS_TO_US(retval);
     154                 :            : }
     155                 :            : 
     156                 :            : /**
     157                 :            :  * Initializes a QH structure.
     158                 :            :  *
     159                 :            :  * @param hcd The HCD state structure for the DWC OTG controller.
     160                 :            :  * @param qh  The QH to init.
     161                 :            :  * @param urb Holds the information about the device/endpoint that we need
     162                 :            :  *            to initialize the QH.
     163                 :            :  */
     164                 :            : #define SCHEDULE_SLOP 10
     165                 :          3 : void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
     166                 :            : {
     167                 :            :         char *speed, *type;
     168                 :            :         int dev_speed;
     169                 :            :         uint32_t hub_addr, hub_port;
     170                 :            :         hprt0_data_t hprt;
     171                 :            : 
     172                 :          3 :         dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
     173                 :          3 :         hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
     174                 :            : 
     175                 :            :         /* Initialize QH */
     176                 :          3 :         qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
     177                 :          3 :         qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
     178                 :            : 
     179                 :          3 :         qh->data_toggle = DWC_OTG_HC_PID_DATA0;
     180                 :          3 :         qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
     181                 :          3 :         DWC_CIRCLEQ_INIT(&qh->qtd_list);
     182                 :          3 :         DWC_LIST_INIT(&qh->qh_list_entry);
     183                 :          3 :         qh->channel = NULL;
     184                 :            : 
     185                 :            :         /* FS/LS Enpoint on HS Hub
     186                 :            :          * NOT virtual root hub */
     187                 :          3 :         dev_speed = hcd->fops->speed(hcd, urb->priv);
     188                 :            : 
     189                 :          3 :         hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
     190                 :          3 :         qh->do_split = 0;
     191                 :          3 :         if (microframe_schedule)
     192                 :          3 :                 qh->speed = dev_speed;
     193                 :            : 
     194                 :          3 :         qh->nak_frame = 0xffff;
     195                 :            : 
     196                 :          3 :         if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED &&
     197                 :            :                         dev_speed != USB_SPEED_HIGH) {
     198                 :            :                 DWC_DEBUGPL(DBG_HCD,
     199                 :            :                             "QH init: EP %d: TT found at hub addr %d, for port %d\n",
     200                 :            :                             dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
     201                 :            :                             hub_port);
     202                 :          2 :                 qh->do_split = 1;
     203                 :          2 :                 qh->skip_count = 0;
     204                 :            :         }
     205                 :            : 
     206                 :          3 :         if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
     207                 :            :                 /* Compute scheduling parameters once and save them. */
     208                 :            : 
     209                 :            :                 /** @todo Account for split transfers in the bus time. */
     210                 :          3 :                 int bytecount =
     211                 :          3 :                     dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
     212                 :            : 
     213                 :          3 :                 qh->usecs =
     214                 :          3 :                     calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
     215                 :          3 :                                   qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
     216                 :            :                                   bytecount);
     217                 :            :                 /* Start in a slightly future (micro)frame. */
     218                 :          3 :                 qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
     219                 :            :                                                     SCHEDULE_SLOP);
     220                 :          3 :                 qh->interval = urb->interval;
     221                 :            : 
     222                 :          3 :                 if (hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) {
     223                 :          2 :                         if (dev_speed == USB_SPEED_LOW ||
     224                 :            :                                         dev_speed == USB_SPEED_FULL) {
     225                 :          2 :                                 qh->interval *= 8;
     226                 :          2 :                                 qh->sched_frame |= 0x7;
     227                 :          2 :                                 qh->start_split_frame = qh->sched_frame;
     228                 :          2 :                         } else if (int_ep_interval_min >= 2 &&
     229                 :          0 :                                         qh->interval < int_ep_interval_min &&
     230                 :          0 :                                         qh->ep_type == UE_INTERRUPT) {
     231                 :          0 :                                 qh->interval = int_ep_interval_min;
     232                 :            :                         }
     233                 :            :                 }
     234                 :            :         }
     235                 :            : 
     236                 :            :         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
     237                 :            :         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
     238                 :            :         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
     239                 :            :                     dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
     240                 :            :         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
     241                 :            :                     dwc_otg_hcd_get_ep_num(&urb->pipe_info),
     242                 :            :                     dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
     243                 :          3 :         switch (dev_speed) {
     244                 :            :         case USB_SPEED_LOW:
     245                 :          2 :                 qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
     246                 :            :                 speed = "low";
     247                 :          2 :                 break;
     248                 :            :         case USB_SPEED_FULL:
     249                 :          1 :                 qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
     250                 :            :                 speed = "full";
     251                 :          1 :                 break;
     252                 :            :         case USB_SPEED_HIGH:
     253                 :          2 :                 qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
     254                 :            :                 speed = "high";
     255                 :          2 :                 break;
     256                 :            :         default:
     257                 :            :                 speed = "?";
     258                 :            :                 break;
     259                 :            :         }
     260                 :            :         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);
     261                 :            : 
     262                 :            :         switch (qh->ep_type) {
     263                 :            :         case UE_ISOCHRONOUS:
     264                 :            :                 type = "isochronous";
     265                 :            :                 break;
     266                 :            :         case UE_INTERRUPT:
     267                 :            :                 type = "interrupt";
     268                 :            :                 break;
     269                 :            :         case UE_CONTROL:
     270                 :            :                 type = "control";
     271                 :            :                 break;
     272                 :            :         case UE_BULK:
     273                 :            :                 type = "bulk";
     274                 :            :                 break;
     275                 :            :         default:
     276                 :            :                 type = "?";
     277                 :            :                 break;
     278                 :            :         }
     279                 :            : 
     280                 :            :         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n", type);
     281                 :            : 
     282                 :            : #ifdef DEBUG
     283                 :            :         if (qh->ep_type == UE_INTERRUPT) {
     284                 :            :                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
     285                 :            :                             qh->usecs);
     286                 :            :                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
     287                 :            :                             qh->interval);
     288                 :            :         }
     289                 :            : #endif
     290                 :            : 
     291                 :          3 : }
     292                 :            : 
     293                 :            : /**
     294                 :            :  * This function allocates and initializes a QH.
     295                 :            :  *
     296                 :            :  * @param hcd The HCD state structure for the DWC OTG controller.
     297                 :            :  * @param urb Holds the information about the device/endpoint that we need
     298                 :            :  *            to initialize the QH.
     299                 :            :  * @param atomic_alloc Flag to do atomic allocation if needed
     300                 :            :  *
     301                 :            :  * @return Returns pointer to the newly allocated QH, or NULL on error. */
     302                 :          3 : dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
     303                 :            :                                     dwc_otg_hcd_urb_t * urb, int atomic_alloc)
     304                 :            : {
     305                 :            :         dwc_otg_qh_t *qh;
     306                 :            : 
     307                 :            :         /* Allocate memory */
     308                 :            :         /** @todo add memflags argument */
     309                 :          3 :         qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
     310                 :          3 :         if (qh == NULL) {
     311                 :          0 :                 DWC_ERROR("qh allocation failed");
     312                 :          0 :                 return NULL;
     313                 :            :         }
     314                 :            : 
     315                 :          3 :         qh_init(hcd, qh, urb);
     316                 :            : 
     317                 :          3 :         if (hcd->core_if->dma_desc_enable
     318                 :          0 :             && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
     319                 :          0 :                 dwc_otg_hcd_qh_free(hcd, qh);
     320                 :          0 :                 return NULL;
     321                 :            :         }
     322                 :            : 
     323                 :          3 :         return qh;
     324                 :            : }
     325                 :            : 
     326                 :            : /* microframe_schedule=0 start */
     327                 :            : 
     328                 :            : /**
     329                 :            :  * Checks that a channel is available for a periodic transfer.
     330                 :            :  *
     331                 :            :  * @return 0 if successful, negative error code otherise.
     332                 :            :  */
     333                 :          0 : static int periodic_channel_available(dwc_otg_hcd_t * hcd)
     334                 :            : {
     335                 :            :         /*
     336                 :            :          * Currently assuming that there is a dedicated host channnel for each
     337                 :            :          * periodic transaction plus at least one host channel for
     338                 :            :          * non-periodic transactions.
     339                 :            :          */
     340                 :            :         int status;
     341                 :            :         int num_channels;
     342                 :            : 
     343                 :          0 :         num_channels = hcd->core_if->core_params->host_channels;
     344                 :          0 :         if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
     345                 :          0 :             && (hcd->periodic_channels < num_channels - 1)) {
     346                 :            :                 status = 0;
     347                 :            :         } else {
     348                 :          0 :                 DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
     349                 :            :                         __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);      //NOTICE
     350                 :            :                 status = -DWC_E_NO_SPACE;
     351                 :            :         }
     352                 :            : 
     353                 :          0 :         return status;
     354                 :            : }
     355                 :            : 
     356                 :            : /**
     357                 :            :  * Checks that there is sufficient bandwidth for the specified QH in the
     358                 :            :  * periodic schedule. For simplicity, this calculation assumes that all the
     359                 :            :  * transfers in the periodic schedule may occur in the same (micro)frame.
     360                 :            :  *
     361                 :            :  * @param hcd The HCD state structure for the DWC OTG controller.
     362                 :            :  * @param qh QH containing periodic bandwidth required.
     363                 :            :  *
     364                 :            :  * @return 0 if successful, negative error code otherwise.
     365                 :            :  */
     366                 :          0 : static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
     367                 :            : {
     368                 :            :         int status;
     369                 :            :         int16_t max_claimed_usecs;
     370                 :            : 
     371                 :            :         status = 0;
     372                 :            : 
     373                 :          0 :         if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
     374                 :            :                 /*
     375                 :            :                  * High speed mode.
     376                 :            :                  * Max periodic usecs is 80% x 125 usec = 100 usec.
     377                 :            :                  */
     378                 :            : 
     379                 :          0 :                 max_claimed_usecs = 100 - qh->usecs;
     380                 :            :         } else {
     381                 :            :                 /*
     382                 :            :                  * Full speed mode.
     383                 :            :                  * Max periodic usecs is 90% x 1000 usec = 900 usec.
     384                 :            :                  */
     385                 :          0 :                 max_claimed_usecs = 900 - qh->usecs;
     386                 :            :         }
     387                 :            : 
     388                 :          0 :         if (hcd->periodic_usecs > max_claimed_usecs) {
     389                 :          0 :                 DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);        //NOTICE
     390                 :            :                 status = -DWC_E_NO_SPACE;
     391                 :            :         }
     392                 :            : 
     393                 :          0 :         return status;
     394                 :            : }
     395                 :            : 
     396                 :            : /* microframe_schedule=0 end */
     397                 :            : 
     398                 :            : /**
     399                 :            :  * Microframe scheduler
     400                 :            :  * track the total use in hcd->frame_usecs
     401                 :            :  * keep each qh use in qh->frame_usecs
     402                 :            :  * when surrendering the qh then donate the time back
     403                 :            :  */
     404                 :            : const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
     405                 :            : 
     406                 :            : /*
     407                 :            :  * called from dwc_otg_hcd.c:dwc_otg_hcd_init
     408                 :            :  */
     409                 :          3 : void init_hcd_usecs(dwc_otg_hcd_t *_hcd)
     410                 :            : {
     411                 :            :         int i;
     412                 :          3 :         if (_hcd->flags.b.port_speed == DWC_HPRT0_PRTSPD_FULL_SPEED) {
     413                 :          1 :                 _hcd->frame_usecs[0] = 900;
     414                 :          1 :                 for (i = 1; i < 8; i++)
     415                 :          1 :                         _hcd->frame_usecs[i] = 0;
     416                 :            :         } else {
     417                 :          3 :                 for (i = 0; i < 8; i++)
     418                 :          3 :                         _hcd->frame_usecs[i] = max_uframe_usecs[i];
     419                 :            :         }
     420                 :          3 : }
     421                 :            : 
     422                 :            : static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
     423                 :            : {
     424                 :            :         int i;
     425                 :            :         unsigned short utime;
     426                 :            :         int t_left;
     427                 :            :         int ret;
     428                 :            :         int done;
     429                 :            : 
     430                 :            :         ret = -1;
     431                 :          3 :         utime = _qh->usecs;
     432                 :            :         t_left = utime;
     433                 :            :         i = 0;
     434                 :            :         done = 0;
     435                 :          3 :         while (done == 0) {
     436                 :            :                 /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
     437                 :          3 :                 if (utime <= _hcd->frame_usecs[i]) {
     438                 :          3 :                         _hcd->frame_usecs[i] -= utime;
     439                 :          3 :                         _qh->frame_usecs[i] += utime;
     440                 :            :                         t_left -= utime;
     441                 :          3 :                         ret = i;
     442                 :            :                         done = 1;
     443                 :            :                         return ret;
     444                 :            :                 } else {
     445                 :          0 :                         i++;
     446                 :          0 :                         if (i == 8) {
     447                 :            :                                 done = 1;
     448                 :            :                                 ret = -1;
     449                 :            :                         }
     450                 :            :                 }
     451                 :            :         }
     452                 :            :         return ret;
     453                 :            :  }
     454                 :            : 
     455                 :            : /*
     456                 :            :  * use this for FS apps that can span multiple uframes
     457                 :            :   */
     458                 :          2 : static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
     459                 :            : {
     460                 :            :         int i;
     461                 :            :         int j;
     462                 :            :         unsigned short utime;
     463                 :            :         int t_left;
     464                 :            :         int ret;
     465                 :            :         int done;
     466                 :            :         unsigned short xtime;
     467                 :            : 
     468                 :            :         ret = -1;
     469                 :          2 :         utime = _qh->usecs;
     470                 :            :         t_left = utime;
     471                 :            :         i = 0;
     472                 :            :         done = 0;
     473                 :            : loop:
     474                 :          2 :         while (done == 0) {
     475                 :          2 :                 if(_hcd->frame_usecs[i] <= 0) {
     476                 :          0 :                         i++;
     477                 :          0 :                         if (i == 8) {
     478                 :            :                                 done = 1;
     479                 :            :                                 ret = -1;
     480                 :            :                         }
     481                 :            :                         goto loop;
     482                 :            :                 }
     483                 :            : 
     484                 :            :                 /*
     485                 :            :                  * we need n consecutive slots
     486                 :            :                  * so use j as a start slot j plus j+1 must be enough time (for now)
     487                 :            :                  */
     488                 :            :                 xtime= _hcd->frame_usecs[i];
     489                 :          2 :                 for (j = i+1 ; j < 8 ; j++ ) {
     490                 :            :                        /*
     491                 :            :                         * if we add this frame remaining time to xtime we may
     492                 :            :                         * be OK, if not we need to test j for a complete frame
     493                 :            :                         */
     494                 :          2 :                        if ((xtime+_hcd->frame_usecs[j]) < utime) {
     495                 :          0 :                                if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
     496                 :            :                                        j = 8;
     497                 :            :                                        ret = -1;
     498                 :          0 :                                        continue;
     499                 :            :                                }
     500                 :            :                        }
     501                 :          2 :                        if (xtime >= utime) {
     502                 :            :                                ret = i;
     503                 :            :                                j = 8;  /* stop loop with a good value ret */
     504                 :          2 :                                continue;
     505                 :            :                        }
     506                 :            :                        /* add the frame time to x time */
     507                 :          0 :                        xtime += _hcd->frame_usecs[j];
     508                 :            :                        /* we must have a fully available next frame or break */
     509                 :          0 :                        if ((xtime < utime)
     510                 :          0 :                                        && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
     511                 :            :                                ret = -1;
     512                 :            :                                j = 8;  /* stop loop with a bad value ret */
     513                 :          0 :                                continue;
     514                 :            :                        }
     515                 :            :                 }
     516                 :          2 :                 if (ret >= 0) {
     517                 :          2 :                         t_left = utime;
     518                 :          2 :                         for (j = i; (t_left>0) && (j < 8); j++ ) {
     519                 :          2 :                                 t_left -= _hcd->frame_usecs[j];
     520                 :          2 :                                 if ( t_left <= 0 ) {
     521                 :          2 :                                         _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
     522                 :          2 :                                         _hcd->frame_usecs[j]= -t_left;
     523                 :            :                                         ret = i;
     524                 :            :                                         done = 1;
     525                 :            :                                 } else {
     526                 :          0 :                                         _qh->frame_usecs[j] += _hcd->frame_usecs[j];
     527                 :          0 :                                         _hcd->frame_usecs[j] = 0;
     528                 :            :                                 }
     529                 :            :                         }
     530                 :            :                 } else {
     531                 :            :                         i++;
     532                 :          0 :                         if (i == 8) {
     533                 :            :                                 done = 1;
     534                 :            :                                 ret = -1;
     535                 :            :                         }
     536                 :            :                 }
     537                 :            :         }
     538                 :          2 :         return ret;
     539                 :            : }
     540                 :            : 
     541                 :          3 : static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
     542                 :            : {
     543                 :            :         int ret;
     544                 :            :         ret = -1;
     545                 :            : 
     546                 :          3 :         if (_qh->speed == USB_SPEED_HIGH ||
     547                 :          3 :                 _hcd->flags.b.port_speed == DWC_HPRT0_PRTSPD_FULL_SPEED) {
     548                 :            :                 /* if this is a hs transaction we need a full frame - or account for FS usecs */
     549                 :          3 :                 ret = find_single_uframe(_hcd, _qh);
     550                 :            :         } else {
     551                 :            :                 /* if this is a fs transaction we may need a sequence of frames */
     552                 :          2 :                 ret = find_multi_uframe(_hcd, _qh);
     553                 :            :         }
     554                 :          3 :         return ret;
     555                 :            : }
     556                 :            : 
     557                 :            : /**
     558                 :            :  * Checks that the max transfer size allowed in a host channel is large enough
     559                 :            :  * to handle the maximum data transfer in a single (micro)frame for a periodic
     560                 :            :  * transfer.
     561                 :            :  *
     562                 :            :  * @param hcd The HCD state structure for the DWC OTG controller.
     563                 :            :  * @param qh QH for a periodic endpoint.
     564                 :            :  *
     565                 :            :  * @return 0 if successful, negative error code otherwise.
     566                 :            :  */
     567                 :          3 : static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
     568                 :            : {
     569                 :            :         int status;
     570                 :            :         uint32_t max_xfer_size;
     571                 :            :         uint32_t max_channel_xfer_size;
     572                 :            : 
     573                 :            :         status = 0;
     574                 :            : 
     575                 :          3 :         max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
     576                 :          3 :         max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
     577                 :            : 
     578                 :          3 :         if (max_xfer_size > max_channel_xfer_size) {
     579                 :          0 :                 DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
     580                 :            :                                 __func__, max_xfer_size, max_channel_xfer_size);        //NOTICE
     581                 :            :                 status = -DWC_E_NO_SPACE;
     582                 :            :         }
     583                 :            : 
     584                 :          3 :         return status;
     585                 :            : }
     586                 :            : 
     587                 :            : 
     588                 :            : 
     589                 :            : /**
     590                 :            :  * Schedules an interrupt or isochronous transfer in the periodic schedule.
     591                 :            :  *
     592                 :            :  * @param hcd The HCD state structure for the DWC OTG controller.
     593                 :            :  * @param qh QH for the periodic transfer. The QH should already contain the
     594                 :            :  * scheduling information.
     595                 :            :  *
     596                 :            :  * @return 0 if successful, negative error code otherwise.
     597                 :            :  */
     598                 :          3 : static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
     599                 :            : {
     600                 :            :         int status = 0;
     601                 :            : 
     602                 :          3 :         if (microframe_schedule) {
     603                 :            :                 int frame;
     604                 :          3 :                 status = find_uframe(hcd, qh);
     605                 :            :                 frame = -1;
     606                 :          3 :                 if (status == 0) {
     607                 :            :                         frame = 7;
     608                 :            :                 } else {
     609                 :          0 :                         if (status > 0 )
     610                 :          0 :                                 frame = status-1;
     611                 :            :                 }
     612                 :            : 
     613                 :            :                 /* Set the new frame up */
     614                 :          3 :                 if (frame > -1) {
     615                 :          3 :                         qh->sched_frame &= ~0x7;
     616                 :          3 :                         qh->sched_frame |= (frame & 7);
     617                 :            :                 }
     618                 :            : 
     619                 :          3 :                 if (status != -1)
     620                 :            :                         status = 0;
     621                 :            :         } else {
     622                 :          0 :                 status = periodic_channel_available(hcd);
     623                 :          0 :                 if (status) {
     624                 :          0 :                         DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);    //NOTICE
     625                 :          0 :                         return status;
     626                 :            :                 }
     627                 :            : 
     628                 :          0 :                 status = check_periodic_bandwidth(hcd, qh);
     629                 :            :         }
     630                 :          3 :         if (status) {
     631                 :          0 :                 DWC_INFO("%s: Insufficient periodic bandwidth for "
     632                 :            :                             "periodic transfer.\n", __func__);
     633                 :          0 :                 return -DWC_E_NO_SPACE;
     634                 :            :         }
     635                 :          3 :         status = check_max_xfer_size(hcd, qh);
     636                 :          3 :         if (status) {
     637                 :          0 :                 DWC_INFO("%s: Channel max transfer size too small "
     638                 :            :                             "for periodic transfer.\n", __func__);
     639                 :          0 :                 return status;
     640                 :            :         }
     641                 :            : 
     642                 :          3 :         if (hcd->core_if->dma_desc_enable) {
     643                 :            :                 /* Don't rely on SOF and start in ready schedule */
     644                 :          0 :                 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
     645                 :            :         }
     646                 :            :         else {
     647                 :          3 :                 if(fiq_enable && (DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame)))
     648                 :            :                 {
     649                 :          3 :                         hcd->fiq_state->next_sched_frame = qh->sched_frame;
     650                 :            : 
     651                 :            :                 }
     652                 :            :                 /* Always start in the inactive schedule. */
     653                 :          3 :                 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
     654                 :            :         }
     655                 :            : 
     656                 :          3 :         if (!microframe_schedule) {
     657                 :            :                 /* Reserve the periodic channel. */
     658                 :          0 :                 hcd->periodic_channels++;
     659                 :            :         }
     660                 :            : 
     661                 :            :         /* Update claimed usecs per (micro)frame. */
     662                 :          3 :         hcd->periodic_usecs += qh->usecs;
     663                 :            : 
     664                 :          3 :         return status;
     665                 :            : }
     666                 :            : 
     667                 :            : 
     668                 :            : /**
     669                 :            :  * This function adds a QH to either the non periodic or periodic schedule if
     670                 :            :  * it is not already in the schedule. If the QH is already in the schedule, no
     671                 :            :  * action is taken.
     672                 :            :  *
     673                 :            :  * @return 0 if successful, negative error code otherwise.
     674                 :            :  */
     675                 :          3 : int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
     676                 :            : {
     677                 :            :         int status = 0;
     678                 :          3 :         gintmsk_data_t intr_mask = {.d32 = 0 };
     679                 :            : 
     680                 :          3 :         if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
     681                 :            :                 /* QH already in a schedule. */
     682                 :            :                 return status;
     683                 :            :         }
     684                 :            : 
     685                 :            :         /* Add the new QH to the appropriate schedule */
     686                 :          3 :         if (dwc_qh_is_non_per(qh)) {
     687                 :            :                 /* Always start in the inactive schedule. */
     688                 :          3 :                 DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
     689                 :            :                                      &qh->qh_list_entry);
     690                 :            :                 //hcd->fiq_state->kick_np_queues = 1;
     691                 :            :         } else {
     692                 :          3 :                 status = schedule_periodic(hcd, qh);
     693                 :          3 :                 if ( !hcd->periodic_qh_count ) {
     694                 :          3 :                         intr_mask.b.sofintr = 1;
     695                 :          3 :                         if (fiq_enable) {
     696                 :          3 :                                 local_fiq_disable();
     697                 :          3 :                                 fiq_fsm_spin_lock(&hcd->fiq_state->lock);
     698                 :          3 :                                 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
     699                 :          3 :                                 fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
     700                 :          3 :                                 local_fiq_enable();
     701                 :            :                         } else {
     702                 :          0 :                                 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
     703                 :            :                         }
     704                 :            :                 }
     705                 :          3 :                 hcd->periodic_qh_count++;
     706                 :            :         }
     707                 :            : 
     708                 :          3 :         return status;
     709                 :            : }
     710                 :            : 
     711                 :            : /**
     712                 :            :  * Removes an interrupt or isochronous transfer from the periodic schedule.
     713                 :            :  *
     714                 :            :  * @param hcd The HCD state structure for the DWC OTG controller.
     715                 :            :  * @param qh QH for the periodic transfer.
     716                 :            :  */
     717                 :          3 : static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
     718                 :            : {
     719                 :            :         int i;
     720                 :          3 :         DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
     721                 :            : 
     722                 :            :         /* Update claimed usecs per (micro)frame. */
     723                 :          3 :         hcd->periodic_usecs -= qh->usecs;
     724                 :            : 
     725                 :          3 :         if (!microframe_schedule) {
     726                 :            :                 /* Release the periodic channel reservation. */
     727                 :          0 :                 hcd->periodic_channels--;
     728                 :            :         } else {
     729                 :          3 :                 for (i = 0; i < 8; i++) {
     730                 :          3 :                         hcd->frame_usecs[i] += qh->frame_usecs[i];
     731                 :          3 :                         qh->frame_usecs[i] = 0;
     732                 :            :                 }
     733                 :            :         }
     734                 :          3 : }
     735                 :            : 
     736                 :            : /**
     737                 :            :  * Removes a QH from either the non-periodic or periodic schedule.  Memory is
     738                 :            :  * not freed.
     739                 :            :  *
     740                 :            :  * @param hcd The HCD state structure.
     741                 :            :  * @param qh QH to remove from schedule. */
     742                 :          3 : void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
     743                 :            : {
     744                 :          3 :         gintmsk_data_t intr_mask = {.d32 = 0 };
     745                 :            : 
     746                 :          3 :         if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
     747                 :            :                 /* QH is not in a schedule. */
     748                 :          3 :                 return;
     749                 :            :         }
     750                 :            : 
     751                 :          3 :         if (dwc_qh_is_non_per(qh)) {
     752                 :          3 :                 if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
     753                 :          3 :                         hcd->non_periodic_qh_ptr =
     754                 :          3 :                             hcd->non_periodic_qh_ptr->next;
     755                 :            :                 }
     756                 :          3 :                 DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
     757                 :            :                 //if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive))
     758                 :            :                 //      hcd->fiq_state->kick_np_queues = 1;
     759                 :            :         } else {
     760                 :          3 :                 deschedule_periodic(hcd, qh);
     761                 :          3 :                 hcd->periodic_qh_count--;
     762                 :          3 :                 if( !hcd->periodic_qh_count && !fiq_fsm_enable ) {
     763                 :          1 :                         intr_mask.b.sofintr = 1;
     764                 :          1 :                         if (fiq_enable) {
     765                 :          1 :                                 local_fiq_disable();
     766                 :          1 :                                 fiq_fsm_spin_lock(&hcd->fiq_state->lock);
     767                 :          1 :                                 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
     768                 :          1 :                                 fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
     769                 :          1 :                                 local_fiq_enable();
     770                 :            :                         } else {
     771                 :          0 :                                 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
     772                 :            :                         }
     773                 :            :                 }
     774                 :            :         }
     775                 :            : }
     776                 :            : 
     777                 :            : /**
     778                 :            :  * Deactivates a QH. For non-periodic QHs, removes the QH from the active
     779                 :            :  * non-periodic schedule. The QH is added to the inactive non-periodic
     780                 :            :  * schedule if any QTDs are still attached to the QH.
     781                 :            :  *
     782                 :            :  * For periodic QHs, the QH is removed from the periodic queued schedule. If
     783                 :            :  * there are any QTDs still attached to the QH, the QH is added to either the
     784                 :            :  * periodic inactive schedule or the periodic ready schedule and its next
     785                 :            :  * scheduled frame is calculated. The QH is placed in the ready schedule if
     786                 :            :  * the scheduled frame has been reached already. Otherwise it's placed in the
     787                 :            :  * inactive schedule. If there are no QTDs attached to the QH, the QH is
     788                 :            :  * completely removed from the periodic schedule.
     789                 :            :  */
     790                 :          3 : void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
     791                 :            :                                int sched_next_periodic_split)
     792                 :            : {
     793                 :          3 :         if (dwc_qh_is_non_per(qh)) {
     794                 :          3 :                 dwc_otg_hcd_qh_remove(hcd, qh);
     795                 :          3 :                 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
     796                 :            :                         /* Add back to inactive non-periodic schedule. */
     797                 :          3 :                         dwc_otg_hcd_qh_add(hcd, qh);
     798                 :            :                         //hcd->fiq_state->kick_np_queues = 1;
     799                 :            :                 } else {
     800                 :          3 :                         if(nak_holdoff && qh->do_split) {
     801                 :          2 :                                 qh->nak_frame = 0xFFFF;
     802                 :            :                         }
     803                 :            :                 }
     804                 :            :         } else {
     805                 :          3 :                 uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
     806                 :            : 
     807                 :          3 :                 if (qh->do_split) {
     808                 :            :                         /* Schedule the next continuing periodic split transfer */
     809                 :          2 :                         if (sched_next_periodic_split) {
     810                 :            : 
     811                 :          0 :                                 qh->sched_frame = frame_number;
     812                 :            : 
     813                 :          0 :                                 if (dwc_frame_num_le(frame_number,
     814                 :            :                                                      dwc_frame_num_inc
     815                 :            :                                                      (qh->start_split_frame,
     816                 :            :                                                       1))) {
     817                 :            :                                         /*
     818                 :            :                                          * Allow one frame to elapse after start
     819                 :            :                                          * split microframe before scheduling
     820                 :            :                                          * complete split, but DONT if we are
     821                 :            :                                          * doing the next start split in the
     822                 :            :                                          * same frame for an ISOC out.
     823                 :            :                                          */
     824                 :          0 :                                         if ((qh->ep_type != UE_ISOCHRONOUS) ||
     825                 :            :                                             (qh->ep_is_in != 0)) {
     826                 :          0 :                                                 qh->sched_frame =
     827                 :            :                                                     dwc_frame_num_inc(qh->sched_frame, 1);
     828                 :            :                                         }
     829                 :            :                                 }
     830                 :            :                         } else {
     831                 :          2 :                                 qh->sched_frame =
     832                 :          2 :                                     dwc_frame_num_inc(qh->start_split_frame,
     833                 :            :                                                       qh->interval);
     834                 :          2 :                                 if (dwc_frame_num_le
     835                 :            :                                     (qh->sched_frame, frame_number)) {
     836                 :          2 :                                         qh->sched_frame = frame_number;
     837                 :            :                                 }
     838                 :          2 :                                 qh->sched_frame |= 0x7;
     839                 :          2 :                                 qh->start_split_frame = qh->sched_frame;
     840                 :            :                         }
     841                 :            :                 } else {
     842                 :          3 :                         qh->sched_frame =
     843                 :          3 :                             dwc_frame_num_inc(qh->sched_frame, qh->interval);
     844                 :          3 :                         if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
     845                 :          1 :                                 qh->sched_frame = frame_number;
     846                 :            :                         }
     847                 :            :                 }
     848                 :            : 
     849                 :          3 :                 if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
     850                 :          3 :                         dwc_otg_hcd_qh_remove(hcd, qh);
     851                 :            :                 } else {
     852                 :            :                         /*
     853                 :            :                          * Remove from periodic_sched_queued and move to
     854                 :            :                          * appropriate queue.
     855                 :            :                          */
     856                 :          3 :                         if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
     857                 :          0 :                         (!microframe_schedule && qh->sched_frame == frame_number)) {
     858                 :          3 :                                 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
     859                 :            :                                                    &qh->qh_list_entry);
     860                 :            :                         } else {
     861                 :          3 :                                 if(fiq_enable && !dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame))
     862                 :            :                                 {
     863                 :          3 :                                         hcd->fiq_state->next_sched_frame = qh->sched_frame;
     864                 :            :                                 }
     865                 :            : 
     866                 :          3 :                                 DWC_LIST_MOVE_HEAD
     867                 :            :                                     (&hcd->periodic_sched_inactive,
     868                 :            :                                      &qh->qh_list_entry);
     869                 :            :                         }
     870                 :            :                 }
     871                 :            :         }
     872                 :          3 : }
     873                 :            : 
     874                 :            : /**
     875                 :            :  * This function allocates and initializes a QTD.
     876                 :            :  *
     877                 :            :  * @param urb The URB to create a QTD from.  Each URB-QTD pair will end up
     878                 :            :  *            pointing to each other so each pair should have a unique correlation.
     879                 :            :  * @param atomic_alloc Flag to do atomic alloc if needed
     880                 :            :  *
     881                 :            :  * @return Returns pointer to the newly allocated QTD, or NULL on error. */
     882                 :          3 : dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
     883                 :            : {
     884                 :            :         dwc_otg_qtd_t *qtd;
     885                 :            : 
     886                 :          3 :         qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
     887                 :          3 :         if (qtd == NULL) {
     888                 :            :                 return NULL;
     889                 :            :         }
     890                 :            : 
     891                 :          3 :         dwc_otg_hcd_qtd_init(qtd, urb);
     892                 :          3 :         return qtd;
     893                 :            : }
     894                 :            : 
     895                 :            : /**
     896                 :            :  * Initializes a QTD structure.
     897                 :            :  *
     898                 :            :  * @param qtd The QTD to initialize.
     899                 :            :  * @param urb The URB to use for initialization.  */
     900                 :          3 : void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
     901                 :            : {
     902                 :          3 :         dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
     903                 :          3 :         qtd->urb = urb;
     904                 :          3 :         if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
     905                 :            :                 /*
     906                 :            :                  * The only time the QTD data toggle is used is on the data
     907                 :            :                  * phase of control transfers. This phase always starts with
     908                 :            :                  * DATA1.
     909                 :            :                  */
     910                 :          3 :                 qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
     911                 :          3 :                 qtd->control_phase = DWC_OTG_CONTROL_SETUP;
     912                 :            :         }
     913                 :            : 
     914                 :            :         /* start split */
     915                 :          3 :         qtd->complete_split = 0;
     916                 :          3 :         qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
     917                 :          3 :         qtd->isoc_split_offset = 0;
     918                 :          3 :         qtd->in_process = 0;
     919                 :            : 
     920                 :            :         /* Store the qtd ptr in the urb to reference what QTD. */
     921                 :          3 :         urb->qtd = qtd;
     922                 :          3 :         return;
     923                 :            : }
     924                 :            : 
     925                 :            : /**
     926                 :            :  * This function adds a QTD to the QTD-list of a QH.  It will find the correct
     927                 :            :  * QH to place the QTD into.  If it does not find a QH, then it will create a
     928                 :            :  * new QH. If the QH to which the QTD is added is not currently scheduled, it
     929                 :            :  * is placed into the proper schedule based on its EP type.
     930                 :            :  * HCD lock must be held and interrupts must be disabled on entry
     931                 :            :  *
     932                 :            :  * @param[in] qtd The QTD to add
     933                 :            :  * @param[in] hcd The DWC HCD structure
     934                 :            :  * @param[out] qh out parameter to return queue head
     935                 :            :  * @param atomic_alloc Flag to do atomic alloc if needed
     936                 :            :  *
     937                 :            :  * @return 0 if successful, negative error code otherwise.
     938                 :            :  */
     939                 :          3 : int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
     940                 :            :                         dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
     941                 :            : {
     942                 :            :         int retval = 0;
     943                 :          3 :         dwc_otg_hcd_urb_t *urb = qtd->urb;
     944                 :            : 
     945                 :            :         /*
     946                 :            :          * Get the QH which holds the QTD-list to insert to. Create QH if it
     947                 :            :          * doesn't exist.
     948                 :            :          */
     949                 :          3 :         if (*qh == NULL) {
     950                 :          3 :                 *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
     951                 :          3 :                 if (*qh == NULL) {
     952                 :            :                         retval = -DWC_E_NO_MEMORY;
     953                 :            :                         goto done;
     954                 :            :                 } else {
     955                 :          3 :                         if (fiq_enable)
     956                 :          3 :                                 hcd->fiq_state->kick_np_queues = 1;
     957                 :            :                 }
     958                 :            :         }
     959                 :          3 :         retval = dwc_otg_hcd_qh_add(hcd, *qh);
     960                 :          3 :         if (retval == 0) {
     961                 :          3 :                 DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
     962                 :            :                                         qtd_list_entry);
     963                 :          3 :                 qtd->qh = *qh;
     964                 :            :         }
     965                 :            : done:
     966                 :            : 
     967                 :          3 :         return retval;
     968                 :            : }
     969                 :            : 
     970                 :            : #endif /* DWC_DEVICE_ONLY */
    

Generated by: LCOV version 1.14