From: Greg KH <gregkh@suse.de>
To: torvalds@linux-foundation.org
Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
Andiry Xu <andiry.xu@amd.com>,
Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: Randy Dunlap <rdunlap@xenotime.net>
Subject: [patch 3/3] USB: xHCI: prevent infinite loop when processing MSE event
Date: Mon, 19 Sep 2011 16:05:12 -0700 [thread overview]
Message-ID: <20110919230833.571044961@clark.kroah.org> (raw)
In-Reply-To: <20110919230920.GA6555@kroah.com>
From: Andiry Xu <andiry.xu@amd.com>
When a xHC host is unable to handle isochronous transfer in the interval,
it reports a Missed Service Error event and skips some tds.
Currently xhci driver handles MSE event in the following ways:
1. When encounter a MSE event, set ep->skip flag, update event ring dequeue
pointer and return.
2. When encounter the next event on this ep, the driver will run the do-while
loop, fetch td from ep's td_list to find the td corresponding to this event.
All tds missed are marked as short transfer(-EXDEV).
The do-while loop will end in two ways:
1. If the td pointed by the event trb is found;
2. If the ep ring's td_list is empty.
However, if a buggy HW reports some unpredicted event (for example, an overrun
event following a MSE event while the ep ring is actually not empty), the
driver will never find the td, and it will loop until the td_list is empty.
Unfortunately, the spinlock is dropped when give back a urb in the do-while
loop. During the spinlock released period, the class driver may still
submit urbs and add tds to the td_list. This may cause disaster, since the
td_list will never be empty and the loop never ends, and the system hangs.
To fix this, count the number of TDs on the ep ring before skipping TDs, and
quit the loop when skipped that number of tds. This guarantees the do-while
loop will end after certain number of cycles, and driver will not be trapped
in an infinite loop.
Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/usb/host/xhci-ring.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1934,8 +1934,10 @@ static int handle_tx_event(struct xhci_h
int status = -EINPROGRESS;
struct urb_priv *urb_priv;
struct xhci_ep_ctx *ep_ctx;
+ struct list_head *tmp;
u32 trb_comp_code;
int ret = 0;
+ int td_num = 0;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
@@ -1957,6 +1959,12 @@ static int handle_tx_event(struct xhci_h
return -ENODEV;
}
+ /* Count current td numbers if ep->skip is set */
+ if (ep->skip) {
+ list_for_each(tmp, &ep_ring->td_list)
+ td_num++;
+ }
+
event_dma = le64_to_cpu(event->buffer);
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
/* Look for common error cases */
@@ -2068,7 +2076,18 @@ static int handle_tx_event(struct xhci_h
goto cleanup;
}
+ /* We've skipped all the TDs on the ep ring when ep->skip set */
+ if (ep->skip && td_num == 0) {
+ ep->skip = false;
+ xhci_dbg(xhci, "All tds on the ep_ring skipped. "
+ "Clear skip flag.\n");
+ ret = 0;
+ goto cleanup;
+ }
+
td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
+ if (ep->skip)
+ td_num--;
/* Is this a TRB in the currently executing TD? */
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
prev parent reply other threads:[~2011-09-19 23:10 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-19 23:09 [patch 0/3] Staging and USB fixes for 3.1 Greg KH
2011-09-19 23:05 ` [patch 1/3] staging: fix comedi build when ISA_DMA_API is enabled but COMEDI_PCI is not enabled Greg KH
2011-09-19 23:05 ` [patch 2/3] USB: xhci: Set change bit when warm reset change is set Greg KH
2011-09-20 11:22 ` Sergei Shtylyov
2011-09-20 12:58 ` Greg KH
2011-09-19 23:05 ` Greg KH [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110919230833.571044961@clark.kroah.org \
--to=gregkh@suse.de \
--cc=andiry.xu@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=sarah.a.sharp@linux.intel.com \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®