Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dwc_otg: root port and FIQ bugfixes #352

Merged
merged 3 commits into from
Aug 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,12 @@ static int __init dwc_otg_driver_init(void)
int retval = 0;
int error;
struct device_driver *drv;

if(fiq_split_enable && !fiq_fix_enable) {
printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n");
fiq_fix_enable = 1;
}

printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
DWC_DRIVER_VERSION,
#ifdef LM_INTERFACE
Expand Down
44 changes: 38 additions & 6 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ static int last_sel_trans_num_avail_hc_at_end = 0;

extern int g_next_sched_frame, g_np_count, g_np_sent;

extern haint_data_t haint_saved;
extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS];
extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS];
extern gintsts_data_t ginsts_saved;

dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
{
return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
Expand Down Expand Up @@ -168,31 +173,43 @@ static void del_timers(dwc_otg_hcd_t * hcd)

/**
* Processes all the URBs in a single list of QHs. Completes them with
* -ETIMEDOUT and frees the QTD.
* -ESHUTDOWN and frees the QTD.
*/
static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
{
dwc_list_link_t *qh_item;
dwc_list_link_t *qh_item, *qh_tmp;
dwc_otg_qh_t *qh;
dwc_otg_qtd_t *qtd, *qtd_tmp;

DWC_LIST_FOREACH(qh_item, qh_list) {
DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
&qh->qtd_list, qtd_list_entry) {
qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
if (qtd->urb != NULL) {
hcd->fops->complete(hcd, qtd->urb->priv,
qtd->urb, -DWC_E_TIMEOUT);
qtd->urb, -DWC_E_SHUTDOWN);
dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
}

}
if(qh->channel) {
/* Using hcchar.chen == 1 is not a reliable test.
* It is possible that the channel has already halted
* but not yet been through the IRQ handler.
*/
dwc_otg_hc_halt(hcd->core_if, qh->channel,
DWC_OTG_HC_XFER_URB_DEQUEUE);
if(microframe_schedule)
hcd->available_host_channels++;
qh->channel = NULL;
}
dwc_otg_hcd_qh_remove(hcd, qh);
}
}

/**
* Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
* Responds with an error status of ESHUTDOWN to all URBs in the non-periodic
* and periodic schedules. The QTD associated with each URB is removed from
* the schedule and freed. This function may be called when a disconnect is
* detected or when the HCD is being stopped.
Expand Down Expand Up @@ -278,7 +295,8 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p)
*/
dwc_otg_hcd->flags.b.port_connect_status_change = 1;
dwc_otg_hcd->flags.b.port_connect_status = 0;

if(fiq_fix_enable)
local_fiq_disable();
/*
* Shutdown any transfers in process by clearing the Tx FIFO Empty
* interrupt mask and status bits and disabling subsequent host
Expand Down Expand Up @@ -374,8 +392,22 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p)
channel->qh = NULL;
}
}
if(fiq_split_enable) {
for(i=0; i < 128; i++) {
dwc_otg_hcd->hub_port[i] = 0;
}
haint_saved.d32 = 0;
for(i=0; i < MAX_EPS_CHANNELS; i++) {
hcint_saved[i].d32 = 0;
hcintmsk_saved[i].d32 = 0;
}
}

}

if(fiq_fix_enable)
local_fiq_enable();

if (dwc_otg_hcd->fops->disconnect) {
dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
}
Expand Down
7 changes: 7 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2660,6 +2660,13 @@ 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];
if(hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
/* We are responding to a channel disable. Driver
* state is cleared - our qtd has gone away.
*/
release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status);
return 1;
}
qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);

hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
Expand Down
11 changes: 11 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
case -DWC_E_OVERFLOW:
status = -EOVERFLOW;
break;
case -DWC_E_SHUTDOWN:
status = -ESHUTDOWN;
break;
default:
if (status) {
DWC_PRINTF("Uknown urb status %d\n", status);
Expand Down Expand Up @@ -794,11 +797,19 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
#if USB_URB_EP_LINKING
usb_hcd_unlink_urb_from_ep(hcd, urb);
#endif
DWC_FREE(dwc_otg_urb);
urb->hcpriv = NULL;
if (retval == -DWC_E_NO_DEVICE)
retval = -ENODEV;
}
}
#if USB_URB_EP_LINKING
else
{
DWC_FREE(dwc_otg_urb);
urb->hcpriv = NULL;
}
#endif
DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
return retval;
}
Expand Down