diff options
author | Terin Stock <terin@terinstock.com> | 2018-09-10 00:24:31 -0400 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2018-12-05 04:13:14 -0500 |
commit | 6ed30a7d8ec29d3aba46e47aa8b4a44f077dda4e (patch) | |
tree | 75c572da124c9259ddfd1fbf18d94aacd8480c29 | |
parent | 47b6f8bf870035d420614844de5e308abe505e8a (diff) |
usb: dwc2: host: use hrtimer for NAK retries
Modify the wait delay utilize the high resolution timer API to allow for
more precisely scheduled callbacks.
A previous commit added a 1ms retry delay after multiple consecutive
NAKed transactions using jiffies. On systems with a low timer interrupt
frequency, this delay may be significantly longer than specified,
resulting in misbehavior with some USB devices.
This scenario was reached on a Raspberry Pi 3B with a Macally FDD-USB
floppy drive (identified as 0424:0fdc Standard Microsystems Corp.
Floppy, based on the USB97CFDC USB FDC). With the relay delay, the drive
would be unable to mount a disk, replying with NAKs until the device was
reset.
Using ktime, the delta between starting the timer (in dwc2_hcd_qh_add)
and the callback function can be determined. With the original delay
implementation, this value was consistently approximately 12ms. (output
in us).
<idle>-0 [000] ..s. 1600.559974: dwc2_wait_timer_fn: wait_timer delta: 11976
<idle>-0 [000] ..s. 1600.571974: dwc2_wait_timer_fn: wait_timer delta: 11977
<idle>-0 [000] ..s. 1600.583974: dwc2_wait_timer_fn: wait_timer delta: 11976
<idle>-0 [000] ..s. 1600.595974: dwc2_wait_timer_fn: wait_timer delta: 11977
After converting the relay delay to using a higher resolution timer, the
delay was much closer to 1ms.
<idle>-0 [000] d.h. 1956.553017: dwc2_wait_timer_fn: wait_timer delta: 1002
<idle>-0 [000] d.h. 1956.554114: dwc2_wait_timer_fn: wait_timer delta: 1002
<idle>-0 [000] d.h. 1957.542660: dwc2_wait_timer_fn: wait_timer delta: 1004
<idle>-0 [000] d.h. 1957.543701: dwc2_wait_timer_fn: wait_timer delta: 1002
The floppy drive operates properly with delays up to approximately 5ms,
and sends NAKs for any delays that are longer.
Fixes: 38d2b5fb75c1 ("usb: dwc2: host: Don't retry NAKed transactions right away")
Cc: <stable@vger.kernel.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Acked-by: Minas Harutyunyan <hminas@synopsys.com>
Signed-off-by: Terin Stock <terin@terinstock.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
-rw-r--r-- | drivers/usb/dwc2/hcd.h | 2 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_queue.c | 19 |
2 files changed, 13 insertions, 8 deletions
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 3f9bccc95add..c089ffa1f0a8 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h | |||
@@ -366,7 +366,7 @@ struct dwc2_qh { | |||
366 | u32 desc_list_sz; | 366 | u32 desc_list_sz; |
367 | u32 *n_bytes; | 367 | u32 *n_bytes; |
368 | struct timer_list unreserve_timer; | 368 | struct timer_list unreserve_timer; |
369 | struct timer_list wait_timer; | 369 | struct hrtimer wait_timer; |
370 | struct dwc2_tt *dwc_tt; | 370 | struct dwc2_tt *dwc_tt; |
371 | int ttport; | 371 | int ttport; |
372 | unsigned tt_buffer_dirty:1; | 372 | unsigned tt_buffer_dirty:1; |
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 40839591d2ec..ea3aa640c15c 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c | |||
@@ -59,7 +59,7 @@ | |||
59 | #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5)) | 59 | #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5)) |
60 | 60 | ||
61 | /* If we get a NAK, wait this long before retrying */ | 61 | /* If we get a NAK, wait this long before retrying */ |
62 | #define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1)) | 62 | #define DWC2_RETRY_WAIT_DELAY 1*1E6L |
63 | 63 | ||
64 | /** | 64 | /** |
65 | * dwc2_periodic_channel_available() - Checks that a channel is available for a | 65 | * dwc2_periodic_channel_available() - Checks that a channel is available for a |
@@ -1464,10 +1464,12 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg, | |||
1464 | * qh back to the "inactive" list, then queues transactions. | 1464 | * qh back to the "inactive" list, then queues transactions. |
1465 | * | 1465 | * |
1466 | * @t: Pointer to wait_timer in a qh. | 1466 | * @t: Pointer to wait_timer in a qh. |
1467 | * | ||
1468 | * Return: HRTIMER_NORESTART to not automatically restart this timer. | ||
1467 | */ | 1469 | */ |
1468 | static void dwc2_wait_timer_fn(struct timer_list *t) | 1470 | static enum hrtimer_restart dwc2_wait_timer_fn(struct hrtimer *t) |
1469 | { | 1471 | { |
1470 | struct dwc2_qh *qh = from_timer(qh, t, wait_timer); | 1472 | struct dwc2_qh *qh = container_of(t, struct dwc2_qh, wait_timer); |
1471 | struct dwc2_hsotg *hsotg = qh->hsotg; | 1473 | struct dwc2_hsotg *hsotg = qh->hsotg; |
1472 | unsigned long flags; | 1474 | unsigned long flags; |
1473 | 1475 | ||
@@ -1491,6 +1493,7 @@ static void dwc2_wait_timer_fn(struct timer_list *t) | |||
1491 | } | 1493 | } |
1492 | 1494 | ||
1493 | spin_unlock_irqrestore(&hsotg->lock, flags); | 1495 | spin_unlock_irqrestore(&hsotg->lock, flags); |
1496 | return HRTIMER_NORESTART; | ||
1494 | } | 1497 | } |
1495 | 1498 | ||
1496 | /** | 1499 | /** |
@@ -1521,7 +1524,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, | |||
1521 | /* Initialize QH */ | 1524 | /* Initialize QH */ |
1522 | qh->hsotg = hsotg; | 1525 | qh->hsotg = hsotg; |
1523 | timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0); | 1526 | timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0); |
1524 | timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0); | 1527 | hrtimer_init(&qh->wait_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
1528 | qh->wait_timer.function = &dwc2_wait_timer_fn; | ||
1525 | qh->ep_type = ep_type; | 1529 | qh->ep_type = ep_type; |
1526 | qh->ep_is_in = ep_is_in; | 1530 | qh->ep_is_in = ep_is_in; |
1527 | 1531 | ||
@@ -1690,7 +1694,7 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) | |||
1690 | * won't do anything anyway, but we want it to finish before we free | 1694 | * won't do anything anyway, but we want it to finish before we free |
1691 | * memory. | 1695 | * memory. |
1692 | */ | 1696 | */ |
1693 | del_timer_sync(&qh->wait_timer); | 1697 | hrtimer_cancel(&qh->wait_timer); |
1694 | 1698 | ||
1695 | dwc2_host_put_tt_info(hsotg, qh->dwc_tt); | 1699 | dwc2_host_put_tt_info(hsotg, qh->dwc_tt); |
1696 | 1700 | ||
@@ -1716,6 +1720,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) | |||
1716 | { | 1720 | { |
1717 | int status; | 1721 | int status; |
1718 | u32 intr_mask; | 1722 | u32 intr_mask; |
1723 | ktime_t delay; | ||
1719 | 1724 | ||
1720 | if (dbg_qh(qh)) | 1725 | if (dbg_qh(qh)) |
1721 | dev_vdbg(hsotg->dev, "%s()\n", __func__); | 1726 | dev_vdbg(hsotg->dev, "%s()\n", __func__); |
@@ -1734,8 +1739,8 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) | |||
1734 | list_add_tail(&qh->qh_list_entry, | 1739 | list_add_tail(&qh->qh_list_entry, |
1735 | &hsotg->non_periodic_sched_waiting); | 1740 | &hsotg->non_periodic_sched_waiting); |
1736 | qh->wait_timer_cancel = false; | 1741 | qh->wait_timer_cancel = false; |
1737 | mod_timer(&qh->wait_timer, | 1742 | delay = ktime_set(0, DWC2_RETRY_WAIT_DELAY); |
1738 | jiffies + DWC2_RETRY_WAIT_DELAY + 1); | 1743 | hrtimer_start(&qh->wait_timer, delay, HRTIMER_MODE_REL); |
1739 | } else { | 1744 | } else { |
1740 | list_add_tail(&qh->qh_list_entry, | 1745 | list_add_tail(&qh->qh_list_entry, |
1741 | &hsotg->non_periodic_sched_inactive); | 1746 | &hsotg->non_periodic_sched_inactive); |