Skip to content

Commit a8afdd5

Browse files
committed
Enable fiq fix by default. Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh
1 parent 9b2353b commit a8afdd5

File tree

5 files changed

+71
-5
lines changed

5 files changed

+71
-5
lines changed

drivers/usb/host/dwc_otg/dwc_otg_driver.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,10 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = {
241241
};
242242

243243
//Global variable to switch the fiq fix on or off
244-
bool fiq_fix_enable = false;
244+
bool fiq_fix_enable = true;
245+
246+
//Global variable to switch the nak holdoff on or off
247+
bool nak_holdoff_enable = true;
245248

246249

247250
/**
@@ -1086,6 +1089,7 @@ static int __init dwc_otg_driver_init(void)
10861089
return retval;
10871090
}
10881091
printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled");
1092+
printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled");
10891093

10901094
error = driver_create_file(drv, &driver_attr_version);
10911095
#ifdef DEBUG
@@ -1366,9 +1370,10 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
13661370
module_param(microframe_schedule, bool, 0444);
13671371
MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
13681372

1369-
13701373
module_param(fiq_fix_enable, bool, 0444);
13711374
MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix");
1375+
module_param(nak_holdoff_enable, bool, 0444);
1376+
MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff");
13721377

13731378
/** @page "Module Parameters"
13741379
*

drivers/usb/host/dwc_otg/dwc_otg_hcd.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
527527
{
528528
dwc_otg_qh_t *qh;
529529
dwc_otg_qtd_t *urb_qtd;
530+
BUG_ON(!hcd);
531+
BUG_ON(!dwc_otg_urb);
530532

531533
#ifdef DEBUG /* integrity checks (Broadcom) */
532534

@@ -543,14 +545,17 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
543545
return -DWC_E_INVALID;
544546
}
545547
urb_qtd = dwc_otg_urb->qtd;
548+
BUG_ON(!urb_qtd);
546549
if (urb_qtd->qh == NULL) {
547550
DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
548551
return -DWC_E_INVALID;
549552
}
550553
#else
551554
urb_qtd = dwc_otg_urb->qtd;
555+
BUG_ON(!urb_qtd);
552556
#endif
553557
qh = urb_qtd->qh;
558+
BUG_ON(!qh);
554559
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
555560
if (urb_qtd->in_process) {
556561
dump_channel_info(hcd, qh);
@@ -1309,6 +1314,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
13091314
num_channels - hcd->periodic_channels) &&
13101315
!DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
13111316

1317+
qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
1318+
1319+
/*
1320+
* Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
1321+
* we hold off on bulk retransmissions to reduce NAK interrupt overhead for
1322+
* cheeky devices that just hold off using NAKs
1323+
*/
1324+
if (dwc_full_frame_num(qh->nak_frame) == dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
1325+
// Make fiq interrupt run on next frame (i.e. 8 uframes)
1326+
g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
1327+
qh_ptr = DWC_LIST_NEXT(qh_ptr);
1328+
continue;
1329+
}
1330+
else
1331+
qh->nak_frame = 0xffff;
1332+
13121333
if (microframe_schedule) {
13131334
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
13141335
if (hcd->available_host_channels < 1) {
@@ -1321,7 +1342,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
13211342
last_sel_trans_num_nonper_scheduled++;
13221343
#endif /* DEBUG_HOST_CHANNELS */
13231344
}
1324-
qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
13251345

13261346
assign_and_init_hc(hcd, qh);
13271347

drivers/usb/host/dwc_otg/dwc_otg_hcd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ typedef struct dwc_otg_qh {
321321
*/
322322
uint16_t sched_frame;
323323

324+
/*
325+
** Frame a NAK was received on this queue head, used to minimise NAK retransmission
326+
*/
327+
uint16_t nak_frame;
328+
324329
/** (micro)frame at which last start split was initialized. */
325330
uint16_t start_split_frame;
326331

drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ int fiq_done, int_done;
5656
int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected;
5757
static int mphi_int_count = 0 ;
5858

59-
extern bool fiq_fix_enable;
59+
extern bool fiq_fix_enable, nak_holdoff_enable;
60+
61+
hcchar_data_t nak_hcchar;
62+
hctsiz_data_t nak_hctsiz;
63+
hcsplt_data_t nak_hcsplt;
64+
int nak_count;
6065

6166
void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void)
6267
{
@@ -230,7 +235,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
230235
DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31));
231236
mphi_int_count = 0;
232237
}
233-
int_done++;
238+
int_done++;
234239
if((jiffies / HZ) > last_time)
235240
{
236241
/* Once a second output the fiq and irq numbers, useful for debug */
@@ -1418,6 +1423,18 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
14181423
DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
14191424
"NAK Received--\n", hc->hc_num);
14201425

1426+
/*
1427+
* When we get bulk NAKs then remember this so we holdoff on this qh until
1428+
* the beginning of the next frame
1429+
*/
1430+
switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
1431+
case UE_BULK:
1432+
//case UE_INTERRUPT:
1433+
//case UE_CONTROL:
1434+
if (nak_holdoff_enable)
1435+
hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd);
1436+
}
1437+
14211438
/*
14221439
* Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
14231440
* interrupt. Re-start the SSPLIT transfer.

drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
181181
if (microframe_schedule)
182182
qh->speed = dev_speed;
183183

184+
qh->nak_frame = 0xffff;
184185

185186
if (((dev_speed == USB_SPEED_LOW) ||
186187
(dev_speed == USB_SPEED_FULL)) &&
@@ -764,6 +765,24 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
764765
int sched_next_periodic_split)
765766
{
766767
if (dwc_qh_is_non_per(qh)) {
768+
769+
dwc_otg_qh_t *qh_tmp;
770+
dwc_list_link_t *qh_list;
771+
DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive)
772+
{
773+
qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry);
774+
if(qh_tmp == qh)
775+
{
776+
/*
777+
* FIQ is being disabled because this one nevers gets a np_count increment
778+
* This is still not absolutely correct, but it should fix itself with
779+
* just an unnecessary extra interrupt
780+
*/
781+
g_np_sent = g_np_count;
782+
}
783+
}
784+
785+
767786
dwc_otg_hcd_qh_remove(hcd, qh);
768787
if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
769788
/* Add back to inactive non-periodic schedule. */

0 commit comments

Comments
 (0)