fix usb host periodic transfer

This commit is contained in:
yangkai
2012-03-31 16:59:17 +08:00
parent 18ee094ebe
commit a5e5356f7a
5 changed files with 101 additions and 56 deletions

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 ||

View File

@@ -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;
}
}
}