fix usb host periodic transfer
authoryangkai <yk@rock-chips.com>
Sat, 31 Mar 2012 08:59:17 +0000 (16:59 +0800)
committeryangkai <yk@rock-chips.com>
Sat, 31 Mar 2012 08:59:17 +0000 (16:59 +0800)
drivers/usb/dwc_otg/dwc_otg_cil.c
drivers/usb/dwc_otg/dwc_otg_hcd.c
drivers/usb/dwc_otg/dwc_otg_hcd.h
drivers/usb/dwc_otg/dwc_otg_hcd_intr.c
drivers/usb/dwc_otg/dwc_otg_hcd_queue.c

index 1fbd039cfbb00ab76049f561cb395dd0c65e7cb4..36c52a8ea9ce4fbf7225d55a1e7e32c790e6279a 100755 (executable)
@@ -916,12 +916,15 @@ void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if)
        
        /* Initialize Host Configuration Register */
        init_fslspclksel(_core_if);
+       /* we don't need full speed mode */
+       #if 0
        if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) 
        {
                hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
                hcfg.b.fslssupp = 1;
                dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
        }
+       #endif
 
        /* Configure data FIFO sizes */
        if (_core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) 
@@ -2429,7 +2432,9 @@ void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
                {       
                        dwc_write_reg32 (&(in_regs->diepdma), 
                                (uint32_t)_ep->dma_addr);
-                   _ep->dma_addr += _ep->xfer_len;
+                       /* EP0 transfer size may more than one packet, dma address has to update
+                        * kever@rk 20111120 */
+                       _ep->dma_addr += _ep->xfer_len;
                }
        
                /* EP enable, IN data in FIFO */
index 3c186646b6f8fc906cda9172c71fa863515497a8..47f86e6dff8fcc9743767eecedfd28d847667ed5 100755 (executable)
@@ -434,9 +434,9 @@ static void kill_all_urbs(dwc_otg_hcd_t *_hcd)
        kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_inactive);
        kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_active);
        kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_inactive);
-       kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_ready);
-       kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned);
-       kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued);
+//     kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_ready);
+//     kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned);
+//     kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued);
 }
 
 /**
@@ -713,9 +713,9 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
 
        /* Initialize the periodic schedule. */
        INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
 
        /*
         * Create a host channel descriptor for each host channel implemented
@@ -896,9 +896,9 @@ int __devinit host11_hcd_init(struct device *dev)
 
        /* Initialize the periodic schedule. */
        INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
 
        /*
         * Create a host channel descriptor for each host channel implemented
@@ -1089,9 +1089,9 @@ int __devinit host20_hcd_init(struct device *dev)
 
        /* Initialize the periodic schedule. */
        INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
-       INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
+//     INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
 
        /*
         * Create a host channel descriptor for each host channel implemented
@@ -1369,9 +1369,9 @@ void dwc_otg_hcd_free(struct usb_hcd *_hcd)
        qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
        qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
        qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
-       qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
-       qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
-       qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
+//     qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
+//     qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
+//     qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
 
        /* Free memory for the host channels. */
        for (i = 0; i < MAX_EPS_CHANNELS; i++) {
@@ -2832,11 +2832,14 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
 #endif
 
        /* Process entries in the periodic ready list. */
-       qh_ptr = _hcd->periodic_sched_ready.next;
-       while (qh_ptr != &_hcd->periodic_sched_ready &&
-              !list_empty(&_hcd->free_hc_list)) {
-
+       qh_ptr = _hcd->periodic_sched_inactive.next;
+       while (qh_ptr != &_hcd->periodic_sched_inactive) {
                qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+               if(qh->qh_state != QH_READY){
+               qh_ptr = qh_ptr->next;
+               continue;
+               }
+
                assign_and_init_hc(_hcd, qh);
 
                /*
@@ -2844,7 +2847,8 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
                 * periodic assigned schedule.
                 */
                qh_ptr = qh_ptr->next;
-               list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_assigned);
+               //list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_assigned);
+               qh->qh_state = QH_ASSIGNED;
 
                ret_val = DWC_OTG_TRANSACTION_PERIODIC;
        }
@@ -3076,8 +3080,8 @@ static void process_periodic_channels(dwc_otg_hcd_t *_hcd)
                    tx_status.b.ptxfspcavail);
 #endif
 
-       qh_ptr = _hcd->periodic_sched_assigned.next;
-       while (qh_ptr != &_hcd->periodic_sched_assigned) {
+       qh_ptr = _hcd->periodic_sched_inactive.next;
+       while (qh_ptr != &_hcd->periodic_sched_inactive) {
                tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
                if (tx_status.b.ptxqspcavail == 0) {
                        no_queue_space = 1;
@@ -3085,6 +3089,10 @@ static void process_periodic_channels(dwc_otg_hcd_t *_hcd)
                }
 
                qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+               if(qh->qh_state != QH_ASSIGNED){
+               qh_ptr = qh_ptr->next;
+               continue;
+               }
 
                /*
                 * Set a flag if we're queuing high-bandwidth in slave mode.
@@ -3118,7 +3126,8 @@ static void process_periodic_channels(dwc_otg_hcd_t *_hcd)
                         * Move the QH from the periodic assigned schedule to
                         * the periodic queued schedule.
                         */
-                       list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_queued);
+                       //list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_queued);
+                       qh->qh_state = QH_QUEUED;
 
                        /* done queuing high bandwidth */
                        _hcd->core_if->queuing_high_bandwidth = 0;
@@ -3138,7 +3147,7 @@ static void process_periodic_channels(dwc_otg_hcd_t *_hcd)
                DWC_DEBUGPL(DBG_HCDV, "  P Tx FIFO Space Avail (after queue): %d\n",
                            tx_status.b.ptxfspcavail);
 #endif
-               if (!(list_empty(&_hcd->periodic_sched_assigned)) ||
+               if (//!(list_empty(&_hcd->periodic_sched_assigned)) ||
                    no_queue_space || no_fifo_space) {
                        /*
                         * May need to queue more transactions as the request
@@ -3178,8 +3187,9 @@ void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd,
 #endif
        /* Process host channels associated with periodic transfers. */
        if ((_tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
-            _tr_type == DWC_OTG_TRANSACTION_ALL) &&
-           !list_empty(&_hcd->periodic_sched_assigned)) {
+            _tr_type == DWC_OTG_TRANSACTION_ALL) //&&
+           //!list_empty(&_hcd->periodic_sched_assigned)
+           ) {
 
                process_periodic_channels(_hcd);
        }
index 0eb5c19c4c4d3a04043827141fddd679bd673bd5..640bfe60c866f0bff6581ce743ed57220822265f 100755 (executable)
@@ -76,6 +76,15 @@ typedef enum dwc_otg_transaction_type {
        DWC_OTG_TRANSACTION_ALL
 } dwc_otg_transaction_type_e;
 
+/** Transaction types. */
+typedef enum qh_status_type {
+       QH_INACTIVE,
+       QH_ACTIVE,
+       QH_READY,
+       QH_ASSIGNED,
+       QH_QUEUED
+} qh_status_type_e;
+
 /**
  * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
  * interrupt, or isochronous transfer. A single QTD is created for each URB
@@ -169,7 +178,11 @@ typedef struct dwc_otg_qh {
 
        /** Ping state if 1. */
        uint8_t                 ping_state;
-
+       
+       /**
+        * 
+       ****/
+    uint16_t        qh_state;
        /**
         * List of QTDs for this QH.
         */
@@ -276,7 +289,7 @@ typedef struct dwc_otg_hcd {
         * Items move from this list to periodic_sched_assigned as host
         * channels become available during the current frame.
         */
-       struct list_head        periodic_sched_ready;
+       //struct list_head      periodic_sched_ready;
 
        /**
         * List of periodic QHs to be executed in the next frame that are
@@ -285,7 +298,7 @@ typedef struct dwc_otg_hcd {
         * Items move from this list to periodic_sched_queued as the
         * transactions for the QH are queued to the DWC_otg controller.
         */
-       struct list_head        periodic_sched_assigned;
+       //struct list_head      periodic_sched_assigned;
 
        /**
         * List of periodic QHs that have been queued for execution.
@@ -296,7 +309,7 @@ typedef struct dwc_otg_hcd {
         * periodic_sched_ready because it must be rescheduled for the next
         * frame. Otherwise, the item moves to periodic_sched_inactive.
         */
-       struct list_head        periodic_sched_queued;
+       //struct list_head      periodic_sched_queued;
 
        /**
         * Total bandwidth claimed so far for periodic transfers. This value
index 8a1665a001d1b29790e34a67c3c576371b2d215f..f099a90ed96c80129009977df929dcb992f4f3e3 100755 (executable)
@@ -35,7 +35,7 @@
 #include "dwc_otg_driver.h"
 #include "dwc_otg_hcd.h"
 #include "dwc_otg_regs.h"
-
+int csplit_nak = 0;
 /** @file 
  * This file contains the implementation of the HCD Interrupt handlers. 
  */
@@ -190,6 +190,10 @@ int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd)
        qh_entry = _hcd->periodic_sched_inactive.next;
        while (qh_entry != &_hcd->periodic_sched_inactive) {
                qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry);
+               if(qh->qh_state != QH_INACTIVE){
+               qh_entry = qh_entry->next;
+               continue;
+               }
                qh_entry = qh_entry->next;
                if (dwc_frame_num_le(qh->sched_frame, _hcd->frame_number)) {
                    #if 1
@@ -220,7 +224,8 @@ int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd)
                                 * Move QH to the ready list to be executed next
                                 * (micro)frame.
                                 */
-                               list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_ready);
+                               //list_move_tail(&qh->qh_list_entry, &_hcd->periodic_sched_ready);
+                   qh->qh_state = QH_READY;
                        }
                }
        }
@@ -229,10 +234,11 @@ int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd)
        if (tr_type != DWC_OTG_TRANSACTION_NONE) {
                dwc_otg_hcd_queue_transactions(_hcd, tr_type);
 #if 1
-       } else if (list_empty(&_hcd->periodic_sched_inactive) &&
-                  list_empty(&_hcd->periodic_sched_ready) &&
-                  list_empty(&_hcd->periodic_sched_assigned) &&
-                  list_empty(&_hcd->periodic_sched_queued)) {
+       } else if (list_empty(&_hcd->periodic_sched_inactive) //&&
+//                list_empty(&_hcd->periodic_sched_ready) &&
+//                list_empty(&_hcd->periodic_sched_assigned) &&
+//                list_empty(&_hcd->periodic_sched_queued)
+            ) {
                /*
                 * We don't have USB data to send. Unfortunately the
                 * Synopsis block continues to generate interrupts at
@@ -499,11 +505,12 @@ int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
         * in the same relative order as the corresponding start-split transactions 
         * were issued.
         */
-       
-       qh_entry = _dwc_otg_hcd->periodic_sched_queued.next;
-       while (qh_entry != &_dwc_otg_hcd->periodic_sched_queued) {
+       qh_entry = _dwc_otg_hcd->periodic_sched_inactive.next;
+       while (qh_entry != &_dwc_otg_hcd->periodic_sched_inactive) {
                qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry);
                qh_entry = qh_entry->next;
+               if(qh->qh_state != QH_QUEUED)
+               continue;
                hcnum = qh->channel->hc_num;
                if (haint.b2.chint & (1 << hcnum)) {
                        retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, hcnum);
@@ -805,6 +812,8 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
 {
        dwc_otg_transaction_type_e tr_type;
        int free_qtd;
+       int continue_trans = 1;
+
     if((!_qtd)|(_qtd->urb == NULL))
     {
         goto cleanup;
@@ -845,6 +854,11 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
                free_qtd = 0;
                break;
        }
+       if(csplit_nak)
+       {
+               continue_trans = 0;
+               csplit_nak = 0;
+       }
 
 
        deactivate_qh(_hcd, _hc->qh, free_qtd);
@@ -872,11 +886,13 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
                 */
                break;
        }
-
-       /* Try to queue more transfers now that there's a free channel. */
-       tr_type = dwc_otg_hcd_select_transactions(_hcd);
-       if (tr_type != DWC_OTG_TRANSACTION_NONE) {
-               dwc_otg_hcd_queue_transactions(_hcd, tr_type);
+       if(continue_trans)
+       {
+               /* Try to queue more transfers now that there's a free channel. */
+               tr_type = dwc_otg_hcd_select_transactions(_hcd);
+               if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+                       dwc_otg_hcd_queue_transactions(_hcd, tr_type);
+               }
        }
        /*
         * Make sure the start of frame interrupt is enabled now that
@@ -933,8 +949,8 @@ static void halt_channel(dwc_otg_hcd_t *_hcd,
                         * halt to be queued when the periodic schedule is
                         * processed.
                         */
-                       list_move_tail(&_hc->qh->qh_list_entry,
-                                 &_hcd->periodic_sched_assigned);
+                       //list_move_tail(&_hc->qh->qh_list_entry,
+                       //        &_hcd->periodic_sched_assigned);
 
                        /*
                         * Make sure the Periodic Tx FIFO Empty interrupt is
@@ -1216,6 +1232,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd,
                if (_hc->complete_split) {
                        _qtd->error_count = 0;
                }
+               csplit_nak = 1;
                _qtd->complete_split = 0;
                halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);
                goto handle_nak_done;
@@ -1782,6 +1799,8 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd,
                handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd);
        } else if(hcint.b.datatglerr){
             DWC_PRINT("%s, DATA toggle error, Channel %d\n",__func__, _hc->hc_num);
+             save_data_toggle(_hc, _hc_regs, _qtd);    //hzb,设备的第一个USB数据包的data toggle不符合USB协议
+             halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
                                clear_hc_int(_hc_regs,chhltd);
        } else {
                if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
index 2d71e478f25bb7cf356c7eeb694e5d4ada724369..96bf3b8b3935868d91898d31a2fe2a6279965cb6 100755 (executable)
@@ -151,11 +151,6 @@ void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_ur
         * NOT virtual root hub */
        _qh->do_split = 0;
 
-       /* yk@rk 20100625
-        * _urb->dev->tt->hub may be null
-        */
-       if((_urb->dev->tt)&&(!_urb->dev->tt->hub))
-               DWC_PRINT("%s tt->hub null!\n",__func__);
        if (((_urb->dev->speed == USB_SPEED_LOW) || 
             (_urb->dev->speed == USB_SPEED_FULL)) &&
            (_urb->dev->tt) && (_urb->dev->tt->hub)&&
@@ -380,6 +375,7 @@ static int schedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
 
        /* Always start in the inactive schedule. */
        list_add_tail(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive);
+       _qh->qh_state = QH_INACTIVE;
 
        /* Reserve the periodic channel. */
        _hcd->periodic_channels++;
@@ -565,11 +561,13 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched
                         * appropriate queue.
                         */
                        if (_qh->sched_frame == frame_number) {
-                               list_move_tail(&_qh->qh_list_entry,
-                                         &_hcd->periodic_sched_ready);
+                               //list_move_tail(&_qh->qh_list_entry,
+                               //        &_hcd->periodic_sched_ready);
+                   _qh->qh_state = QH_READY;
                        } else {
-                               list_move_tail(&_qh->qh_list_entry,
-                                         &_hcd->periodic_sched_inactive);
+                               //list_move_tail(&_qh->qh_list_entry,
+                               //        &_hcd->periodic_sched_inactive);
+                   _qh->qh_state = QH_INACTIVE;
                        }
                }
        }