From: yangkai Date: Sat, 31 Mar 2012 08:59:17 +0000 (+0800) Subject: fix usb host periodic transfer X-Git-Tag: firefly_0821_release~9530 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=a5e5356f7a0cb792cfa65283ded77e72bbebf3d9;p=firefly-linux-kernel-4.4.55.git fix usb host periodic transfer --- diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c index 1fbd039cfbb0..36c52a8ea9ce 100755 --- a/drivers/usb/dwc_otg/dwc_otg_cil.c +++ b/drivers/usb/dwc_otg/dwc_otg_cil.c @@ -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 */ diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c index 3c186646b6f8..47f86e6dff8f 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c @@ -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); } diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.h b/drivers/usb/dwc_otg/dwc_otg_hcd.h index 0eb5c19c4c4d..640bfe60c866 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd.h +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h @@ -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 diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c index 8a1665a001d1..f099a90ed96c 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c @@ -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 || diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c index 2d71e478f25b..96bf3b8b3935 100755 --- a/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c +++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c @@ -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; } } }