From 792eeb4fc1a60b2c71b61f29234a1b729874d533 Mon Sep 17 00:00:00 2001 From: P33M Date: Mon, 22 Apr 2013 00:08:36 +0100 Subject: [PATCH] dwc_otg: fix NAK holdoff and allow on split transactions only This corrects a bug where if a single active non-periodic endpoint had at least one transaction in its qh, on frnum == MAX_FRNUM the qh would get skipped and never get queued again. This would result in a silent device until error detection (automatic or otherwise) would either reset the device or flush and requeue the URBs. Additionally the NAK holdoff was enabled for all transactions - this would potentially stall a HS endpoint for 1ms if a previous error state enabled this interrupt and the next response was a NAK. Fix so that only split transactions get held off. --- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 28 +++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c index 91eefecd0dbcb5..eaa8f384649ac6 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c @@ -46,7 +46,7 @@ #include "dwc_otg_hcd.h" #include "dwc_otg_regs.h" -extern bool microframe_schedule; +extern bool microframe_schedule, nak_holdoff_enable; //#define DEBUG_HOST_CHANNELS #ifdef DEBUG_HOST_CHANNELS @@ -1349,18 +1349,26 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) /* * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission - * we hold off on bulk retransmissions to reduce NAK interrupt overhead for + * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed * cheeky devices that just hold off using NAKs */ - if (dwc_full_frame_num(qh->nak_frame) == dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { - // Make fiq interrupt run on next frame (i.e. 8 uframes) - g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; - qh_ptr = DWC_LIST_NEXT(qh_ptr); - continue; + if (nak_holdoff_enable && qh->do_split) { + if (qh->nak_frame != 0xffff && + dwc_full_frame_num(qh->nak_frame) == + dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { + /* + * Revisit: Need to avoid trampling on periodic scheduling. + * Currently we are safe because g_np_count != g_np_sent whenever we hit this, + * but if this behaviour is changed then periodic endpoints will get a slower + * polling rate. + */ + g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; + qh_ptr = DWC_LIST_NEXT(qh_ptr); + continue; + } else { + qh->nak_frame = 0xffff; + } } - else - qh->nak_frame = 0xffff; - if (microframe_schedule) { DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); if (hcd->available_host_channels < 1) {