diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2009-08-19 12:22:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:37 -0400 |
commit | a448c9d8c58ff7d3f8cc2a8f835065460099b22d (patch) | |
tree | 418610891b8dc271bbd798ff5c47d921be5f806d /drivers/usb/host/ehci-hcd.c | |
parent | 3a44494e233c0fdd818d485cfea8998500543589 (diff) |
USB: EHCI: change deschedule logic for interrupt QHs
This patch (as1281) changes the way ehci-hcd deschedules interrupt
QHs, copying the approach used for async QHs. The caller is no longer
responsible for rescheduling the QH if its queue is non-empty; instead
the reschedule is done directly by intr_deschedule(), after calling
qh_completions(). This is exactly the same as how end_unlink_async()
works.
ehci_urb_dequeue() and intr_deschedule() now correctly handle the case
where they are called while another interrupt URB for the same QH is
being given back. This was a surprisingly large blind spot. And
scan_periodic() now respects the new needs_rescan flag.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 26 |
1 files changed, 4 insertions, 22 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d7e85b6231b3..4f89d7ffd53a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -934,8 +934,9 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
934 | break; | 934 | break; |
935 | switch (qh->qh_state) { | 935 | switch (qh->qh_state) { |
936 | case QH_STATE_LINKED: | 936 | case QH_STATE_LINKED: |
937 | case QH_STATE_COMPLETING: | ||
937 | intr_deschedule (ehci, qh); | 938 | intr_deschedule (ehci, qh); |
938 | /* FALL THROUGH */ | 939 | break; |
939 | case QH_STATE_IDLE: | 940 | case QH_STATE_IDLE: |
940 | qh_completions (ehci, qh); | 941 | qh_completions (ehci, qh); |
941 | break; | 942 | break; |
@@ -944,23 +945,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
944 | qh, qh->qh_state); | 945 | qh, qh->qh_state); |
945 | goto done; | 946 | goto done; |
946 | } | 947 | } |
947 | |||
948 | /* reschedule QH iff another request is queued */ | ||
949 | if (!list_empty (&qh->qtd_list) | ||
950 | && HC_IS_RUNNING (hcd->state)) { | ||
951 | rc = qh_schedule(ehci, qh); | ||
952 | |||
953 | /* An error here likely indicates handshake failure | ||
954 | * or no space left in the schedule. Neither fault | ||
955 | * should happen often ... | ||
956 | * | ||
957 | * FIXME kill the now-dysfunctional queued urbs | ||
958 | */ | ||
959 | if (rc != 0) | ||
960 | ehci_err(ehci, | ||
961 | "can't reschedule qh %p, err %d", | ||
962 | qh, rc); | ||
963 | } | ||
964 | break; | 948 | break; |
965 | 949 | ||
966 | case PIPE_ISOCHRONOUS: | 950 | case PIPE_ISOCHRONOUS: |
@@ -1079,12 +1063,10 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) | |||
1079 | * while the QH is active. Unlink it now; | 1063 | * while the QH is active. Unlink it now; |
1080 | * re-linking will call qh_refresh(). | 1064 | * re-linking will call qh_refresh(). |
1081 | */ | 1065 | */ |
1082 | if (eptype == USB_ENDPOINT_XFER_BULK) { | 1066 | if (eptype == USB_ENDPOINT_XFER_BULK) |
1083 | unlink_async(ehci, qh); | 1067 | unlink_async(ehci, qh); |
1084 | } else { | 1068 | else |
1085 | intr_deschedule(ehci, qh); | 1069 | intr_deschedule(ehci, qh); |
1086 | (void) qh_schedule(ehci, qh); | ||
1087 | } | ||
1088 | } | 1070 | } |
1089 | } | 1071 | } |
1090 | spin_unlock_irqrestore(&ehci->lock, flags); | 1072 | spin_unlock_irqrestore(&ehci->lock, flags); |