dwc_otg_hcd_ddma.c

Go to the documentation of this file.
00001 /*==========================================================================
00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
00003  * $Revision: #2 $
00004  * $Date: 2009/04/21 $
00005  * $Change: 1237473 $
00006  *
00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
00009  * otherwise expressly agreed to in writing between Synopsys and you.
00010  *
00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
00012  * any End User Software License Agreement or Agreement for Licensed Product
00013  * with Synopsys or any supplement thereto. You are permitted to use and
00014  * redistribute this Software in source and binary forms, with or without
00015  * modification, provided that redistributions of source code must retain this
00016  * notice. You may not view, use, disclose, copy or distribute this file or
00017  * any information contained herein except pursuant to this license grant from
00018  * Synopsys. If you do not agree with this notice, including the disclaimer
00019  * below, then you are not authorized to use the Software.
00020  *
00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00031  * DAMAGE.
00032  * ========================================================================== */
00033 #ifndef DWC_DEVICE_ONLY
00034 
00039 #include "dwc_otg_hcd.h"
00040 #include "dwc_otg_regs.h"
00041                 
00042                 
00043 static inline uint8_t frame_list_idx(uint16_t frame)
00044 {
00045         return (frame & (MAX_FRLIST_EN_NUM - 1));
00046 }
00047 
00048 static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
00049 {
00050         return (idx + inc) & 
00051                 (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1);
00052 }
00053 
00054 static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
00055 {
00056         return (idx - inc) & 
00057                 (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1);
00058 }
00059 
00060 static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
00061 {
00062         return (((qh->ep_type == UE_ISOCHRONOUS) && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)) 
00063                                                         ?
00064                                                         MAX_DMA_DESC_NUM_HS_ISOC
00065                                                         :
00066                                                         MAX_DMA_DESC_NUM_GENERIC);
00067 }
00068 static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
00069 {
00070         return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) 
00071                                                 ? ((qh->interval + 8 - 1) / 8)
00072                                                 :
00073                                                 qh->interval);
00074 }
00075 
00076 static int desc_list_alloc(dwc_otg_qh_t * qh)
00077 {
00078         int retval = 0;
00079         
00080         qh->desc_list = (dwc_otg_host_dma_desc_t *) 
00081                                 dwc_dma_alloc(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
00082                                               &qh->desc_list_dma
00083                                               );
00084         
00085         if (!qh->desc_list) {
00086                 retval = -DWC_E_NO_MEMORY;
00087                 DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
00088                 
00089         }
00090         
00091         dwc_memset(qh->desc_list, 0x00, sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
00092          
00093 
00094         qh->n_bytes = (uint32_t *) dwc_alloc(sizeof(uint32_t) * max_desc_num(qh));
00095         
00096         if (!qh->n_bytes) {
00097                 retval = -DWC_E_NO_MEMORY;
00098                 DWC_ERROR("%s: Failed to allocate array for descriptors' size actual values\n",
00099                           __func__);
00100                 
00101         }       
00102         return retval;
00103 
00104 }
00105 
00106 static void desc_list_free(dwc_otg_qh_t * qh)
00107 {
00108         if(qh->desc_list) {
00109                 dwc_dma_free(max_desc_num(qh), qh->desc_list, qh->desc_list_dma);
00110                 qh->desc_list = NULL;
00111         }
00112         
00113         if (qh->n_bytes) {
00114                 dwc_free(qh->n_bytes);
00115                 qh->n_bytes = NULL;
00116         }
00117 }
00118 
00119 static int frame_list_alloc(dwc_otg_hcd_t * hcd)
00120 {
00121         int retval = 0; 
00122         if (hcd->frame_list)
00123                 return 0;
00124         
00125         hcd->frame_list = dwc_dma_alloc(4 * MAX_FRLIST_EN_NUM,
00126                                         &hcd->frame_list_dma
00127                                         );
00128         if (!hcd->frame_list) {
00129                 retval = -DWC_E_NO_MEMORY;
00130                 DWC_ERROR("%s: Frame List allocation failed\n", __func__);
00131         }
00132         
00133         dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
00134         
00135         return retval;
00136 }
00137 
00138 static void frame_list_free(dwc_otg_hcd_t * hcd)
00139 {
00140         if (!hcd->frame_list)
00141                 return;
00142         
00143         dwc_dma_free(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
00144         hcd->frame_list = NULL;
00145 }
00146 
00147 static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
00148 {
00149                 
00150         hcfg_data_t hcfg;
00151 
00152         hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg);
00153 
00154         if (hcfg.b.perschedstat) {
00155                 /* already enabled*/    
00156                 return;
00157         }
00158         
00159         dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hflbaddr, hcd->frame_list_dma);
00160         
00161         switch(fr_list_en) {
00162         case 64:
00163             hcfg.b.frlisten = 3;
00164             break;
00165         case 32:
00166             hcfg.b.frlisten = 2;
00167             break;
00168         case 16:
00169             hcfg.b.frlisten = 1;    
00170         case 8:
00171             hcfg.b.frlisten = 0;
00172         default:
00173             break;        
00174         }
00175         
00176         hcfg.b.perschedena = 1;
00177 
00178         DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
00179         dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
00180 
00181 }
00182  
00183 static void per_sched_disable(dwc_otg_hcd_t * hcd)
00184 {
00185         hcfg_data_t hcfg;
00186 
00187         hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg);
00188         
00189         if (!hcfg.b.perschedstat) {
00190                 /* already disabled */  
00191                 return;
00192         }
00193         hcfg.b.perschedena = 0;
00194         
00195         DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
00196         dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
00197 }
00198 
00199 /* 
00200  * Activates/Deactivates FrameList entries for the channel 
00201  * based on endpoint servicing period.
00202  */
00203 void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
00204 {
00205         uint16_t i, j, inc;
00206         dwc_hc_t *hc = qh->channel;
00207         
00208         inc = frame_incr_val(qh);
00209         
00210         if (qh->ep_type == UE_ISOCHRONOUS)
00211                 i = frame_list_idx(qh->sched_frame);
00212         else
00213                 i = 0;
00214 
00215         j = i;
00216         do {
00217                 if (enable)
00218                         hcd->frame_list[j] |= (1 << hc->hc_num);
00219                 else
00220                         hcd->frame_list[j] &= ~(1 << hc->hc_num);
00221                 j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
00222         }
00223         while (j != i);
00224         
00225         if (!enable)
00226                 return;
00227         
00228         hc->schinfo = 0;
00229         if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
00230                 j = 1;
00231                 for (i = 0 ; i < 8 / qh->interval; i++) {
00232                         hc->schinfo |= j;
00233                         j = j << qh->interval;
00234                 }
00235         }
00236         else {
00237                 hc->schinfo = 0xff;
00238         }       
00239 }               
00240 #if 1
00241 void dump_frame_list(dwc_otg_hcd_t * hcd)
00242 {
00243         int i = 0;
00244         DWC_PRINTF("--FRAME LIST (hex) --\n");          
00245         for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
00246                 DWC_PRINTF("%x\t",hcd->frame_list[i]);
00247                 if (!(i % 8) && i)    
00248                         DWC_PRINTF("\n");
00249         }
00250         DWC_PRINTF("\n----\n");
00251 
00252 }
00253 #endif
00254 
00255 static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00256 {
00257         dwc_hc_t *hc = qh->channel;
00258         if (dwc_qh_is_non_per(qh)) {
00259                 hcd->non_periodic_channels--;                   
00260         }
00261         else {
00262                 update_frame_list(hcd, qh, 0);
00263         }
00264         /* 
00265          * The condition is added to prevent double cleanup try in case of device
00266          * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
00267          */
00268         if (hc->qh) {   
00269                 dwc_otg_hc_cleanup(hcd->core_if, hc);
00270                 DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
00271                 hc->qh = NULL;
00272         }
00273         
00274         qh->channel = NULL;
00275         qh->ntd = 0;
00276         
00277         if (qh->desc_list) {
00278                 dwc_memset(qh->desc_list, 0x00, 
00279                             sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
00280         }
00281 }
00282 
00294 int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00295 {
00296         int retval = 0;
00297         
00298         if (qh->do_split) {
00299                 DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
00300                 return -1;
00301         }
00302 
00303         retval = desc_list_alloc(qh);
00304         
00305         if ((retval == 0) && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
00306                 if(!hcd->frame_list) {
00307                         retval = frame_list_alloc(hcd); 
00308                         /* Enable periodic schedule on first periodic QH */
00309                         if (retval == 0)                
00310                                 per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
00311                 }
00312         }
00313         
00314         qh->ntd = 0;
00315         
00316         return retval;
00317 }
00318 
00327 void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00328 {
00329         desc_list_free(qh);
00330 
00331         /* 
00332          * Channel still assigned due to some reasons. 
00333          * Seen on Isoc URB dequeue. Channel halted but no subsequent
00334          * ChHalted interrupt to release the channel. Afterwards
00335          * when it comes here from endpoint disable routine
00336          * channel remains assigned.
00337          */
00338         if (qh->channel)
00339                 release_channel_ddma(hcd, qh);
00340 
00341         if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT) 
00342                         && !hcd->periodic_channels && hcd->frame_list) {
00343                 
00344                 per_sched_disable(hcd); 
00345                 frame_list_free(hcd);   
00346         }
00347 }       
00348 
00349 static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
00350 {
00351         if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
00352                 /* 
00353                  * Descriptor set(8 descriptors) index
00354                  * which is 8-aligned.
00355                  */     
00356                 return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
00357         }
00358         else {
00359                 return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
00360         }       
00361 }
00362 
00363 /* 
00364  * Determine starting frame for Isochronous transfer. 
00365  * Few frames skipped to prevent race condition with HC. 
00366  */
00367 static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t* skip_frames)
00368 {
00369         uint16_t frame = 0;
00370         hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
00371         
00372         /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
00373         
00374         /* 
00375          * skip_frames is used to limit activated descriptors number
00376          * to avoid the situation when HC services the last activated
00377          * descriptor firstly.
00378          * Example for FS:
00379          * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
00380          * corresponding to curr_frame+1, the descriptor corresponding to frame 2
00381          * will be fetched. If the number of descriptors is max=64 (or greather) the list will
00382          * be fully programmed with Active descriptors and it is possible case(rare) that the latest 
00383          * descriptor(considering rollback) corresponding to frame 2 will be serviced first.
00384          * HS case is more probable because, in fact, up to 11 uframes(16 in the code)
00385          * may be skipped.
00386          */
00387         if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
00388                 /* 
00389                  * Consider uframe counter also, to start xfer asap.
00390                  * If half of the frame elapsed skip 2 frames otherwise
00391                  * just 1 frame. 
00392                  * Starting descriptor index must be 8-aligned, so
00393                  * if the current frame is near to complete the next one
00394                  * is skipped as well.
00395                  */
00396                         
00397                 if (dwc_micro_frame_num(hcd->frame_number)  >= 5) {
00398                         *skip_frames = 2 * 8;
00399                         frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
00400                 }       
00401                 else {
00402                         *skip_frames = 1 * 8;
00403                         frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
00404                 }       
00405                                  
00406                 frame = dwc_full_frame_num(frame); 
00407         } else {
00408                 /* 
00409                  * Two frames are skipped for FS - the current and the next.
00410                  * But for descriptor programming, 1 frame(descriptor) is enough,
00411                  * see example above.
00412                  */
00413                 *skip_frames = 1;        
00414                 frame = dwc_frame_num_inc(hcd->frame_number, 2);
00415         }
00416         
00417         return frame;
00418 }
00419 /* 
00420  * Calculate initial descriptor index for isochronous transfer
00421  * based on scheduled frame. 
00422  */
00423 static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00424 {
00425         uint16_t frame = 0, fr_idx, fr_idx_tmp; 
00426         uint8_t skip_frames = 0 ;
00427         /* 
00428          * With current ISOC processing algorithm the channel is being
00429          * released when no more QTDs in the list(qh->ntd == 0).
00430          * Thus this function is called only when qh->ntd == 0 and qh->channel == 0. 
00431          *
00432          * So qh->channel != NULL branch is not used and just not removed from the
00433          * source file. It is required for another possible approach which is,
00434          * do not disable and release the channel when ISOC session completed, 
00435          * just move QH to inactive schedule until new QTD arrives. 
00436          * On new QTD, the QH moved back to 'ready' schedule,
00437          * starting frame and therefore starting desc_index are recalculated.
00438          * In this case channel is released only on ep_disable.
00439          */
00440          
00441         /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
00442         if (qh->channel) {
00443                 frame = calc_starting_frame(hcd, qh, &skip_frames);     
00444                 /* 
00445                  * Calculate initial descriptor index based on FrameList current bitmap
00446                  * and servicing period.
00447                  */
00448                 fr_idx_tmp = frame_list_idx(frame);
00449                 fr_idx = (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) - fr_idx_tmp) 
00450                                 % frame_incr_val(qh);
00451                 fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
00452         }
00453         else {
00454                 qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);   
00455                 fr_idx = frame_list_idx(qh->sched_frame);
00456         }
00457         
00458         qh->td_first = qh->td_last =  frame_to_desc_idx(qh, fr_idx);
00459         
00460         return skip_frames;
00461 }
00462  
00463 #define ISOC_URB_GIVEBACK_ASAP
00464  
00465 #define MAX_ISOC_XFER_SIZE_FS 1023
00466 #define MAX_ISOC_XFER_SIZE_HS 3072
00467 #define DESCNUM_THRESHOLD 4
00468 
00469 static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t skip_frames)
00470 {
00471         struct dwc_otg_hcd_iso_packet_desc *frame_desc;
00472         dwc_otg_qtd_t *qtd;
00473         dwc_otg_host_dma_desc_t *dma_desc;
00474         uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
00475         
00476         idx = qh->td_last;
00477         inc = qh->interval;
00478         n_desc = 0;
00479         
00480         ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
00481         if (skip_frames && !qh->channel)
00482                 ntd_max = ntd_max - skip_frames / qh->interval; 
00483         
00484         max_xfer_size = (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS 
00485                                                                  : MAX_ISOC_XFER_SIZE_FS;
00486                         
00487         DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
00488                 while ((qh->ntd < ntd_max) && (qtd->isoc_frame_index_last < qtd->urb->packet_count)) {
00489                                 
00490                         dma_desc = &qh->desc_list[idx];
00491                         dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
00492 
00493                         frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
00494                         
00495                         if (frame_desc->length > max_xfer_size)
00496                                 qh->n_bytes[idx] = max_xfer_size;
00497                         else
00498                                 qh->n_bytes[idx] = frame_desc->length;
00499                         dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
00500                         dma_desc->status.b_isoc.a = 1;
00501                         
00502                         dma_desc->buf = qtd->urb->dma + frame_desc->offset;
00503                         
00504                         qh->ntd++;
00505 
00506                         qtd->isoc_frame_index_last++;
00507                         
00508                 #ifdef  ISOC_URB_GIVEBACK_ASAP
00509                         /* 
00510                          * Set IOC for each descriptor corresponding to the 
00511                          * last frame of the URB.
00512                          */     
00513                         if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
00514                                 dma_desc->status.b_isoc.ioc = 1;
00515                         
00516                 #endif  
00517                         idx = desclist_idx_inc(idx, inc, qh->dev_speed);
00518                         n_desc++;
00519                         
00520                 }
00521                 qtd->in_process = 1;
00522         }
00523         
00524         qh->td_last = idx;
00525         
00526 #ifdef  ISOC_URB_GIVEBACK_ASAP
00527         /* Set IOC for the last descriptor if descriptor list is full */        
00528         if (qh->ntd == ntd_max) {
00529                 idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
00530                 qh->desc_list[idx].status.b_isoc.ioc = 1;
00531         }
00532 #else   
00533         /* 
00534          * Set IOC bit only for one descriptor. 
00535          * Always try to be ahead of HW processing,
00536          * i.e. on IOC generation driver activates next descriptors but
00537          * core continues to process descriptors followed the one with IOC set.
00538          */
00539 
00540         if (n_desc > DESCNUM_THRESHOLD) {
00541                 /* 
00542                  * Move IOC "up". Required even if there is only one QTD 
00543                  * in the list, cause QTDs migth continue to be queued,
00544                  * but during the activation it was only one queued.
00545                  * Actually more than one QTD might be in the list if this function called 
00546                  * from XferCompletion - QTDs was queued during HW processing of the previous
00547                  * descriptor chunk.
00548                  */     
00549                 idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
00550         }
00551         else {
00552                 /* 
00553                  * Set the IOC for the latest descriptor
00554                  * if either number of descriptor is not greather than threshold
00555                  * or no more new descriptors activated.
00556                  */     
00557                 idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
00558         }
00559         
00560         qh->desc_list[idx].status.b_isoc.ioc = 1;
00561 #endif
00562 }
00563 
00564 
00565 static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00566 {
00567 
00568         dwc_hc_t *hc;
00569         dwc_otg_host_dma_desc_t *dma_desc;
00570         dwc_otg_qtd_t *qtd;
00571         int     num_packets, len, n_desc = 0;
00572         
00573         hc =  qh->channel;
00574          
00575         /* 
00576          * Start with hc->xfer_buff initialized in 
00577          * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
00578          * this pointer re-assigned to the buffer of the currently processed QTD.
00579          * For non-SG request there is always one QTD active.
00580          */
00581         
00582         DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
00583                         
00584                 if (n_desc) {
00585                         /* SG request - more than 1 QTDs */
00586                         hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
00587                         hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
00588                 }
00589 
00590                 qtd->n_desc = 0;
00591                 
00592                 do {
00593                         dma_desc = &qh->desc_list[n_desc];
00594                         len = hc->xfer_len;
00595                         
00596 
00597                         if (len > MAX_DMA_DESC_SIZE)
00598                                 len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
00599                         
00600                         if (hc->ep_is_in) {
00601                                 if (len > 0) {
00602                                         num_packets = (len + hc->max_packet - 1) / hc->max_packet;
00603                                 }
00604                                 else {
00605                                         /* Need 1 packet for transfer length of 0. */
00606                                         num_packets = 1;
00607                                 }
00608                                 /* Always program an integral # of max packets for IN transfers. */
00609                                 len = num_packets * hc->max_packet;     
00610                         }                               
00611                                 
00612                         dma_desc->status.b.n_bytes = len;
00613                         
00614                         qh->n_bytes[n_desc] = len;
00615                         
00616 
00617                         if ((qh->ep_type == UE_CONTROL) && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
00618                                 dma_desc->status.b.sup = 1; /* Setup Packet */
00619                                 
00620                         dma_desc->status.b.a = 1; /* Active descriptor */
00621                         
00622                         dma_desc->buf = (uint32_t) hc->xfer_buff;
00623 
00624                         /* 
00625                          * Last descriptor(or single) of IN transfer 
00626                          * with actual size less than MaxPacket.
00627                          */
00628                         if (len > hc->xfer_len) {
00629                                 hc->xfer_len = 0;
00630                         }
00631                         else {
00632                                 hc->xfer_buff += len;
00633                                 hc->xfer_len -= len;
00634                         }
00635                         
00636                         qtd->n_desc++;
00637                         n_desc++;
00638                 }
00639                 while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
00640                 
00641 
00642                 qtd->in_process = 1;
00643                 
00644                 if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
00645                         break;
00646         }
00647 
00648         if (n_desc) {
00649                 /* Request Transfer Complete interrupt for the last descriptor */
00650                 qh->desc_list[n_desc-1].status.b.ioc = 1;
00651                 /* End of List indicator */
00652                 qh->desc_list[n_desc-1].status.b.eol = 1;
00653                 
00654                 hc->ntd = n_desc;
00655         }
00656 }
00657 
00675 void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00676 {
00677         /* Channel is already assigned */
00678         dwc_hc_t *hc = qh->channel;
00679         uint8_t skip_frames = 0;
00680         
00681         switch (hc->ep_type) {
00682         case DWC_OTG_EP_TYPE_CONTROL:
00683         case DWC_OTG_EP_TYPE_BULK:
00684                 init_non_isoc_dma_desc(hcd, qh);
00685                 
00686                 dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
00687                 break;
00688         case DWC_OTG_EP_TYPE_INTR:
00689                 init_non_isoc_dma_desc(hcd, qh);
00690                 
00691                 update_frame_list(hcd, qh, 1);
00692                 
00693                 dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
00694                 break;
00695         case DWC_OTG_EP_TYPE_ISOC:
00696                         
00697                 if(!qh->ntd)
00698                         skip_frames = recalc_initial_desc_idx(hcd, qh);
00699                 
00700                 init_isoc_dma_desc(hcd, qh, skip_frames);
00701 
00702                 if (!hc->xfer_started) {
00703 
00704                         update_frame_list(hcd, qh, 1);
00705                 
00706                         /* 
00707                          * Always set to max, instead of actual size.
00708                          * Otherwise ntd will be changed with 
00709                          * channel being enabled. Not recommended.
00710                          *
00711                          */     
00712                         hc->ntd = max_desc_num(qh);
00713                         /* Enable channel only once for ISOC */ 
00714                         dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
00715                 }
00716                 
00717                 break;
00718         default:
00719                 
00720                 break;
00721         }
00722 }
00723 
00724 static void complete_isoc_xfer_ddma(dwc_otg_hcd_t *hcd,
00725                                    dwc_hc_t *hc,
00726                                    dwc_otg_hc_regs_t *hc_regs,
00727                                    dwc_otg_halt_status_e halt_status)
00728 {
00729         struct dwc_otg_hcd_iso_packet_desc      *frame_desc;            
00730         dwc_otg_qtd_t                           *qtd, *qtd_tmp;
00731         dwc_otg_qh_t                            *qh;
00732         dwc_otg_host_dma_desc_t                 *dma_desc;
00733         uint16_t                                idx, remain;
00734         uint8_t                                 urb_compl;      
00735         
00736         qh = hc->qh;
00737         idx = qh->td_first;
00738         
00739 
00740         if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
00741                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
00742                         qtd->in_process = 0;
00743                 return; 
00744         }
00745         else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) || 
00746                         (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
00747                 /* 
00748                  * Channel is halted in these error cases.
00749                  * Considered as serious issues.
00750                  * Complete all URBs marking all frames as failed, 
00751                  * irrespective whether some of the descriptors(frames) succeeded or no.
00752                  * Pass error code to completion routine as well, to
00753                  * update urb->status, some of class drivers might use it to stop
00754                  * queing transfer requests.
00755                  */     
00756                 int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR) 
00757                                                         ? (-DWC_E_IO)
00758                                                         : (-DWC_E_OVERFLOW);
00759                                                 
00760                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
00761                         for(idx = 0; idx < qtd->urb->packet_count; idx++) {
00762                                 frame_desc = &qtd->urb->iso_descs[idx];
00763                                 frame_desc->status = err;
00764                         }
00765                         hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
00766                         dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
00767                 }
00768                 return; 
00769         }
00770         
00771         
00772         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
00773                 
00774                 if (!qtd->in_process)
00775                     break;
00776                 
00777                 urb_compl = 0;
00778                 
00779                 do {
00780 
00781                         dma_desc = &qh->desc_list[idx];
00782                         
00783                         frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
00784                         remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
00785         
00786                         if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
00787                                 /* 
00788                                  * XactError or, unable to complete all the transactions 
00789                                  * in the scheduled micro-frame/frame, 
00790                                  * both indicated by DMA_DESC_STS_PKTERR.
00791                                  */     
00792                                 qtd->urb->error_count++;
00793                                 frame_desc->actual_length = qh->n_bytes[idx] - remain;
00794                                 frame_desc->status = -DWC_E_PROTOCOL;
00795                         }
00796                         else {
00797                                 /* Success */   
00798                                                                 
00799                                 frame_desc->actual_length = qh->n_bytes[idx] - remain;
00800                                 frame_desc->status = 0;
00801                         }
00802                         
00803                         if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
00804                                 /*
00805                                  * urb->status is not used for isoc transfers here.
00806                                  * The individual frame_desc status are used instead.
00807                                  */
00808 
00809                                 hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
00810                                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
00811                                 
00812                                 /* 
00813                                  * This check is necessary because urb_dequeue can be called 
00814                                  * from urb complete callback(sound driver example).
00815                                  * All pending URBs are dequeued there, so no need for
00816                                  * further processing.
00817                                  */
00818                                 if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {   
00819                                         return;
00820                                 }
00821                                 
00822                                 urb_compl = 1;          
00823                                 
00824                         }
00825                         
00826                         qh->ntd--;
00827                         
00828                         /* Stop if IOC requested descriptor reached */
00829                         if (dma_desc->status.b_isoc.ioc) {
00830                                 idx = desclist_idx_inc(idx, qh->interval, hc->speed);   
00831                                 goto stop_scan;
00832                         }
00833                         
00834                         idx = desclist_idx_inc(idx, qh->interval, hc->speed);
00835                         
00836                         if (urb_compl)
00837                                 break;
00838                 }
00839                 while(idx != qh->td_first);
00840         }
00841 stop_scan:      
00842         qh->td_first = idx;
00843 }
00844         
00845 uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
00846                            dwc_hc_t * hc,
00847                            dwc_otg_qtd_t * qtd,
00848                            dwc_otg_host_dma_desc_t * dma_desc,
00849                            dwc_otg_halt_status_e halt_status,
00850                            uint32_t n_bytes,
00851                            uint8_t *xfer_done)
00852 {
00853 
00854         uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
00855         dwc_otg_hcd_urb_t *urb = qtd->urb;
00856         
00857         
00858         if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
00859                 urb->status = -DWC_E_IO;
00860                 return 1;
00861         }
00862         if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
00863                 switch (halt_status) {
00864                 case DWC_OTG_HC_XFER_STALL:
00865                         urb->status = -DWC_E_PIPE;
00866                         break;
00867                 case DWC_OTG_HC_XFER_BABBLE_ERR:
00868                         urb->status = -DWC_E_OVERFLOW;
00869                         break;
00870                 case DWC_OTG_HC_XFER_XACT_ERR:
00871                         urb->status = -DWC_E_PROTOCOL;
00872                         break;
00873                 default:        
00874                         DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
00875                                   halt_status);
00876                         break;
00877                 }
00878                 return 1;
00879         }
00880         
00881         if (dma_desc->status.b.a == 1) {
00882                 DWC_DEBUGPL(DBG_HCDV, "Active descriptor encountered on channel %d\n", hc->hc_num);
00883                 return 0;
00884         }
00885         
00886         if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
00887             if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
00888                 urb->actual_length += n_bytes - remain;
00889                 if (remain || urb->actual_length == urb->length) {
00890                         /* 
00891                          * For Control Data stage do not set urb->status=0 to prevent
00892                          * URB callback. Set it when Status phase done. See below.
00893                          */
00894                         *xfer_done = 1;
00895                 }               
00896             
00897             }
00898             else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
00899                 urb->status = 0;
00900                 *xfer_done = 1;
00901             }
00902             /* No handling for SETUP stage */
00903 
00904         }
00905         else { 
00906             /* BULK and INTR */
00907             urb->actual_length += n_bytes - remain;
00908             if (remain || urb->actual_length == urb->length) {
00909                 urb->status = 0;
00910                 *xfer_done = 1;
00911             }
00912         }
00913 
00914         return 0;
00915 }
00916 
00917 static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
00918                                         dwc_hc_t * hc,
00919                                         dwc_otg_hc_regs_t * hc_regs,
00920                                         dwc_otg_halt_status_e halt_status)
00921 {
00922         dwc_otg_hcd_urb_t       *urb = NULL;
00923         dwc_otg_qtd_t           *qtd, *qtd_tmp;
00924         dwc_otg_qh_t            *qh;
00925         dwc_otg_host_dma_desc_t *dma_desc;
00926         uint32_t                n_bytes, n_desc, i;
00927         uint8_t                 failed = 0, xfer_done;
00928         
00929         n_desc = 0;
00930         
00931         qh = hc->qh;
00932 
00933         
00934         if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
00935                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
00936                         qtd->in_process = 0;
00937                 }
00938                 return;
00939         }
00940         
00941         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
00942                 
00943                 urb = qtd->urb;
00944 
00945                 n_bytes = 0; 
00946                 xfer_done = 0; 
00947                 
00948                 for (i = 0; i < qtd->n_desc; i++) {
00949                         dma_desc = &qh->desc_list[n_desc];
00950                 
00951                         n_bytes = qh->n_bytes[n_desc];
00952                         
00953                         
00954                         failed = update_non_isoc_urb_state_ddma(hcd, hc, qtd, dma_desc, 
00955                                                                 halt_status, n_bytes, &xfer_done);
00956                         
00957                         if (failed || (xfer_done && (urb->status != -DWC_E_IN_PROGRESS))) {
00958                                 
00959                                 hcd->fops->complete(hcd, urb->priv, urb, urb->status);
00960                                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
00961 
00962                                 if (failed)
00963                                         goto stop_scan;
00964                         }
00965                         else if (qh->ep_type == UE_CONTROL) {
00966                                 if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
00967                                         if (urb->length > 0) {
00968                                                 qtd->control_phase = DWC_OTG_CONTROL_DATA;
00969                                         } else {
00970                                                 qtd->control_phase = DWC_OTG_CONTROL_STATUS;
00971                                         }
00972                                         DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction done\n");
00973                                 }
00974                                 else if(qtd->control_phase == DWC_OTG_CONTROL_DATA) {
00975                                         if (xfer_done) {
00976                                                 qtd->control_phase = DWC_OTG_CONTROL_STATUS;
00977                                                 DWC_DEBUGPL(DBG_HCDV, "  Control data transfer done\n");
00978                                         } else if (i+1 == qtd->n_desc){
00979                                                 /* 
00980                                                  * Last descriptor for Control data stage which is
00981                                                  * not completed yet.
00982                                                  */     
00983                                                 dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
00984                                         }
00985                                 }
00986                         }
00987                         
00988                         n_desc++;
00989                 }
00990                 
00991         }
00992         
00993 stop_scan:      
00994         
00995         if (qh->ep_type != UE_CONTROL) {
00996                 /* 
00997                  * Resetting the data toggle for bulk
00998                  * and interrupt endpoints in case of stall. See handle_hc_stall_intr() 
00999                  */     
01000                 if (halt_status == DWC_OTG_HC_XFER_STALL) {     
01001                         qh->data_toggle = DWC_OTG_HC_PID_DATA0; 
01002                 }
01003                 else {
01004                         dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
01005                 }
01006         }
01007         
01008         if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
01009                 hcint_data_t hcint;
01010                 hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
01011                 if (hcint.b.nyet) {
01012                         /*
01013                          * Got a NYET on the last transaction of the transfer. It
01014                          * means that the endpoint should be in the PING state at the
01015                          * beginning of the next transfer.
01016                          */
01017                         qh->ping_state = 1;
01018                         clear_hc_int(hc_regs, nyet);
01019                 }
01020 
01021         }
01022 
01023 }
01024 
01042 void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t *hcd,
01043                             dwc_hc_t *hc,
01044                             dwc_otg_hc_regs_t *hc_regs,
01045                             dwc_otg_halt_status_e halt_status)
01046 {
01047         uint8_t continue_isoc_xfer = 0;
01048         dwc_otg_transaction_type_e tr_type;
01049         dwc_otg_qh_t *qh = hc->qh;
01050         
01051         if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
01052 
01053                 complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
01054                 
01055                 /* Release the channel if halted or session completed */        
01056                 if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
01057                                 DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
01058 
01059                         /* Halt the channel if session completed */     
01060                         if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
01061                                 dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
01062                         }       
01063                         
01064                         release_channel_ddma(hcd, qh);
01065                         dwc_otg_hcd_qh_remove(hcd, qh);
01066                 }
01067                 else {
01068                         /* Keep in assigned schedule to continue transfer */
01069                         DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
01070                                            &qh->qh_list_entry);
01071                         continue_isoc_xfer = 1;
01072                                 
01073                 }
01077         }
01078         else {
01079                 /* Scan descriptor list to complete the URB(s), then release the channel */     
01080                 complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
01081                 
01082                 release_channel_ddma(hcd, qh);
01083                 
01084                 dwc_otg_hcd_qh_remove(hcd, qh);
01085                 
01086                 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
01087                         /* Add back to inactive non-periodic schedule on normal completion */
01088                         dwc_otg_hcd_qh_add(hcd, qh);
01089                 }
01090         
01091 
01092         }
01093         tr_type = dwc_otg_hcd_select_transactions(hcd);
01094         if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
01095                 if (continue_isoc_xfer) {
01096                         if (tr_type == DWC_OTG_TRANSACTION_NONE) {
01097                                 tr_type = DWC_OTG_TRANSACTION_PERIODIC;
01098                         } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
01099                                 tr_type = DWC_OTG_TRANSACTION_ALL;
01100                         }
01101                 }
01102                 dwc_otg_hcd_queue_transactions(hcd, tr_type);
01103         }
01104 }
01105         
01106 #endif  /* DWC_DEVICE_ONLY */

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.4.7