update for rk30 usbhost multicore process

This commit is contained in:
yangkai
2012-05-19 11:00:26 +08:00
parent 10f680f3cc
commit cbb6f08877
6 changed files with 91 additions and 53 deletions

2
drivers/usb/core/hcd.c Normal file → Executable file
View File

@@ -1583,8 +1583,8 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
/* pass ownership to the completion handler */
urb->status = status;
urb->complete (urb);
atomic_dec (&urb->use_count);
urb->complete (urb);
if (unlikely(atomic_read(&urb->reject)))
wake_up (&usb_kill_urb_queue);
usb_put_urb (urb);

View File

@@ -904,7 +904,6 @@ void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if)
fifosize_data_t ptxfifosize;
int i;
hcchar_data_t hcchar;
hcfg_data_t hcfg;
dwc_otg_hc_regs_t *hc_regs;
int num_channels;
gotgctl_data_t gotgctl = {.d32 = 0};

View File

@@ -392,7 +392,6 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list
struct list_head *qtd_item;
dwc_otg_qtd_t *qtd;
struct urb *urb;
struct usb_host_endpoint *ep;
list_for_each(qh_item, _qh_list) {
qh = list_entry(qh_item, dwc_otg_qh_t, qh_list_entry);
@@ -401,22 +400,11 @@ static void kill_urbs_in_qh_list(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list
qtd_item = qh->qtd_list.next) {
qtd = list_entry(qtd_item, dwc_otg_qtd_t, qtd_list_entry);
if (qtd->urb != NULL) {
urb = qtd->urb;
ep = qtd->urb->ep;
urb = qtd->urb;
// 20110415 yk
// urb will be re entry to ep->urb_list if use ETIMEOUT
dwc_otg_hcd_complete_urb(_hcd, qtd->urb,
-ETIMEDOUT);//ESHUTDOWN
//if(!list_empty(&ep->urb_list))
DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n",
__func__, urb, usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "IN" : "OUT", urb->unlinked);
if (!urb->unlinked)
urb->unlinked = -ESHUTDOWN;
dwc_otg_hcd_complete_urb(_hcd, urb,
-ESHUTDOWN);//ETIMEDOUT,ENOENT
}
dwc_otg_hcd_qtd_remove_and_free(qtd);
}
@@ -486,9 +474,11 @@ static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if );
}
spin_lock(&dwc_otg_hcd->global_lock);
/* Respond with an error status to all URBs in the schedule. */
kill_all_urbs(dwc_otg_hcd);
spin_unlock(&dwc_otg_hcd->global_lock);
if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
/* Clean up any host channels that were in use. */
@@ -694,6 +684,9 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
/* Initialize the DWC OTG HCD. */
dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
spin_lock_init(&dwc_otg_hcd->global_lock);
dwc_otg_hcd->core_if = otg_dev->core_if;
otg_dev->hcd = dwc_otg_hcd;
@@ -885,6 +878,8 @@ int __devinit host11_hcd_init(struct device *dev)
dwc_otg_hcd->host_enabled = 0;
#endif
spin_lock_init(&dwc_otg_hcd->global_lock);
/* Register the HCD CIL Callbacks */
dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if,
@@ -1078,6 +1073,7 @@ int __devinit host20_hcd_init(struct device *dev)
dwc_otg_hcd->host_enabled = 0;
#endif
spin_lock_init(&dwc_otg_hcd->global_lock);
/* Register the HCD CIL Callbacks */
dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if,
@@ -1243,10 +1239,12 @@ int dwc_otg_hcd_start(struct usb_hcd *_hcd)
{
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
unsigned long flags;
struct usb_bus *bus;
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
local_irq_save(flags);
bus = hcd_to_bus(_hcd);
_hcd->state = HC_STATE_RUNNING;
@@ -1285,6 +1283,7 @@ int dwc_otg_hcd_start(struct usb_hcd *_hcd)
}
hcd_reinit(dwc_otg_hcd);
out:
local_irq_restore(flags);
return 0;
}
@@ -1502,20 +1501,20 @@ int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd,
int retval;
dwc_otg_hcd_t * dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
dwc_otg_qtd_t * qtd;
#if 0
retval = usb_hcd_link_urb_to_ep(_hcd, _urb);
if (retval)
{
DWC_PRINT("%s, usb_hcd_link_urb_to_ep error\n", __func__);
return retval;
}
#endif
if(atomic_read(&_urb->use_count)>1){
retval = -EPERM;
dump_stack();
DWC_PRINT("%s urb %p already in queue, qtd %p, count%d\n", __func__, _urb, _urb->hcpriv, atomic_read(&_urb->use_count));
goto out;
}
#ifdef DEBUG
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
dump_urb_info(_urb, "dwc_otg_hcd_urb_enqueue");
}
#endif /* */
if (!dwc_otg_hcd->flags.b.port_connect_status) {
DWC_ERROR("DWC OTG No longer connected\n");
/* No longer connected. */
retval = -ENODEV;
goto out;
@@ -1544,7 +1543,6 @@ int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd,
DWC_SOF_INTR_MASK);
#endif
out:
return retval;
}
@@ -1556,26 +1554,33 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
dwc_otg_hcd_t * dwc_otg_hcd;
dwc_otg_qtd_t * urb_qtd;
dwc_otg_qh_t * qh;
struct usb_host_endpoint *_ep = _urb->ep;//dwc_urb_to_endpoint(_urb);
//int retval;
struct usb_host_endpoint *_ep;
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
local_irq_save(flags);
urb_qtd = (dwc_otg_qtd_t *) _urb->hcpriv;
if(((uint32_t)_urb&0xf0000000)==0)
DWC_PRINT("%s urb is %p\n", __func__, _urb);
_ep = dwc_urb_to_endpoint(_urb);
if(_ep==NULL)
{
DWC_PRINT("%s=====================================================\n",__func__);
DWC_PRINT("urb->ep is null\n");
return -1;
}
qh = (dwc_otg_qh_t *) _ep->hcpriv;
if(urb_qtd == NULL)
urb_qtd = (dwc_otg_qtd_t *) _urb->hcpriv;
if(((uint32_t)urb_qtd&0xf0000000) == 0)
{
DWC_PRINT("%s,urb_qtd is null\n",__func__);
goto urb_qtd_null;
//return -1;
DWC_PRINT("%s,urb_qtd is %p urb %p, count %d\n",__func__, urb_qtd, _urb, atomic_read(&_urb->use_count));
if((atomic_read(&_urb->use_count)) == 0)
return 0;
else
return -1;
}
qh = (dwc_otg_qh_t *) _ep->hcpriv;
dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
#ifdef DEBUG
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
@@ -1590,6 +1595,7 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
if (urb_qtd == qh->qtd_in_process) {
/* The QTD is in process (it has been assigned to a channel). */
if (dwc_otg_hcd->flags.b.port_connect_status) {
DWC_PRINT("%s urb %p in process\n", __func__, _urb);
/*
* If still connected (i.e. in host mode), halt the
@@ -1616,10 +1622,8 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
dwc_otg_hcd_qh_remove(dwc_otg_hcd, qh);
}
local_irq_restore(flags);
urb_qtd_null:
_urb->hcpriv = NULL;
//usb_hcd_unlink_urb_from_ep(_hcd, _urb);
spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
/* Higher layer software sets URB status. */
usb_hcd_giveback_urb(_hcd, _urb, _status);
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
@@ -1637,9 +1641,12 @@ void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd,
struct usb_host_endpoint *_ep)
{
unsigned long flags;
dwc_otg_qh_t *qh;
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
"endpoint=%d\n", _ep->desc.bEndpointAddress,
dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress));
@@ -1658,6 +1665,8 @@ void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd,
_ep->hcpriv = NULL;
}
spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
return;
}
@@ -1668,8 +1677,17 @@ void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd,
* This function is called by the USB core when an interrupt occurs */
irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *_hcd)
{
irqreturn_t result;
unsigned long flags;
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
return IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd));
spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
result = IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd));
spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
return result;
}
/** Creates Status Change bitmap for the root hub and root port. The bitmap is
@@ -2228,6 +2246,7 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
u16 _wLength)
{
int retval = 0;
unsigned long flags;
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
dwc_otg_core_if_t *core_if = hcd_to_dwc_otg_hcd (_hcd)->core_if;
@@ -2235,6 +2254,7 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
hprt0_data_t hprt0 = {.d32 = 0};
uint32_t port_status;
spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
switch (_typeReq) {
case ClearHubFeature:
@@ -2491,11 +2511,13 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
hprt0.b.prtrst = 1;
dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
}
spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
// kever @rk 20110712
// can not use mdelay(60) while irq disable
//MDELAY (60);
msleep(60);
spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
hprt0.b.prtrst = 0;
dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
break;
@@ -2628,6 +2650,7 @@ int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
break;
}
spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
return retval;
}
@@ -3240,7 +3263,9 @@ __acquires(_hcd->lock)
_urb->status = _status;
_urb->hcpriv = NULL;
spin_unlock(&_hcd->global_lock);
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(_hcd), _urb, _status);
spin_lock(&_hcd->global_lock);
}
void dwc_otg_clear_halt(struct urb *_urb)

View File

@@ -379,6 +379,8 @@ typedef struct dwc_otg_hcd {
/* Tasket to do a reset */
struct tasklet_struct *reset_tasklet;
spinlock_t global_lock;
#ifdef DEBUG
uint32_t frrem_samples;
uint64_t frrem_accum;
@@ -498,7 +500,7 @@ static inline void dwc_otg_hcd_qh_remove_and_free (dwc_otg_hcd_t *_hcd,
* @return Returns the memory allocate or NULL on error. */
static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc (void)
{
return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_KERNEL);
return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_ATOMIC);//GFP_KERNEL
}
extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *urb);
@@ -509,7 +511,7 @@ extern int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *dwc_otg_hcd);
* @return Returns the memory allocate or NULL on error. */
static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc (void)
{
return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL);
return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_ATOMIC);//GFP_KERNEL
}
/** Frees the memory for a QTD structure. QTD should already be removed from

View File

@@ -482,17 +482,17 @@ int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
{
int retval = 0;
haint_data_t haint;
volatile haint_data_t haint;
int hcnum;
struct list_head *qh_entry;
dwc_otg_qh_t *qh;
int i;
/* Clear appropriate bits in HCINTn to clear the interrupt bit in
* GINTSTS */
haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if);
#if 0
int i;
for (i = 0; i < _dwc_otg_hcd->core_if->core_params->host_channels; i++) {
if (haint.b2.chint & (1 << i))
retval |= dwc_otg_hcd_handle_hc_n_intr(_dwc_otg_hcd, i);
@@ -511,23 +511,31 @@ int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
qh_entry = qh_entry->next;
if(qh->qh_state != QH_QUEUED)
continue;
if(qh->channel == NULL){
DWC_PRINT("%s channel NULL 1\n", __func__);
break;
}
hcnum = qh->channel->hc_num;
if (haint.b2.chint & (1 << hcnum)) {
retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, hcnum);
}
}
haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if);
qh_entry = _dwc_otg_hcd->non_periodic_sched_active.next;
while (&_dwc_otg_hcd->non_periodic_sched_active != qh_entry){
qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry);
qh_entry = qh_entry->next;
if(qh->channel == NULL){
DWC_PRINT("%s channel NULL 2\n", __func__);
break;
}
hcnum = qh->channel->hc_num;
if (haint.b2.chint & (1 << hcnum)) {
retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, hcnum);
}
}
haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if);
int i;
for (i = 0; i < _dwc_otg_hcd->core_if->core_params->host_channels; i++) {
if (haint.b2.chint & (1 << i))
retval |= dwc_otg_hcd_handle_hc_n_intr(_dwc_otg_hcd, i);
@@ -814,10 +822,15 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
int free_qtd;
int continue_trans = 1;
if((!_qtd)|(_qtd->urb == NULL))
{
if(((uint32_t) _qtd & 0xf0000000)==0){
DWC_PRINT("%s qtd %p, status %d\n", __func__, _qtd, _halt_status);
goto cleanup;
}
if(((uint32_t) _qtd->urb & 0xf0000000)==0){
DWC_PRINT("%s urb %p, status %d\n", __func__, _qtd->urb, _halt_status);
goto cleanup;
}
DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n",
__func__, _hc->hc_num, _halt_status);
switch (_halt_status) {
@@ -1459,6 +1472,7 @@ static int32_t handle_hc_babble_intr(dwc_otg_hcd_t *_hcd,
{
DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
"Babble Error--\n", _hc->hc_num);
DWC_PRINT("%s \n", __func__);
if (_hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EOVERFLOW);
halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
@@ -1555,6 +1569,7 @@ static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t *_hcd,
if((_qtd==NULL)||(_qtd->urb == NULL))
{
DWC_PRINT("%s qtd->urb %p NULL\n", __func__, _qtd);
goto out;
}
switch (usb_pipetype(_qtd->urb->pipe)) {
@@ -1874,7 +1889,6 @@ int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num
hc = _dwc_otg_hcd->hc_ptr_array[_num];
hc_regs = _dwc_otg_hcd->core_if->host_if->hc_regs[_num];
qtd = list_entry(hc->qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry);
hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",

View File

@@ -145,7 +145,6 @@ void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_ur
_qh->maxp = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe)));
INIT_LIST_HEAD(&_qh->qtd_list);
INIT_LIST_HEAD(&_qh->qh_list_entry);
_qh->channel = NULL;
/* FS/LS Enpoint on HS Hub
* NOT virtual root hub */
@@ -645,7 +644,6 @@ int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *_qtd,
struct urb *urb = _qtd->urb;
/*
* Get the QH which holds the QTD-list to insert to. Create QH if it
* doesn't exist.
@@ -660,15 +658,15 @@ int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *_qtd,
}
ep->hcpriv = qh;
}
local_irq_save(flags);
spin_lock_irqsave(&_dwc_otg_hcd->global_lock, flags);
retval = dwc_otg_hcd_qh_add(_dwc_otg_hcd, qh);
if (retval == 0) {
list_add_tail(&_qtd->qtd_list_entry, &qh->qtd_list);
}
spin_unlock_irqrestore(&_dwc_otg_hcd->global_lock, flags);
done:
local_irq_restore(flags);
return retval;
}