diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-07-11 11:22:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 19:54:26 -0400 |
commit | 8c5bf7be56f1a8aecc1f802f132d53f556a9bc45 (patch) | |
tree | d3b22a284f3f81b804bf9898928f866cfb8a45cd /drivers | |
parent | 55934eb3b9fa52eb53b9d7342267fc73c38206aa (diff) |
USB: EHCI: don't refcount iso_stream structures
This patch (as1580) makes ehci_iso_stream structures behave more like
QHs, in that they will remain allocated until their isochronous
endpoint is disabled. This will come in useful in the future, when
periodic bandwidth gets allocated as an altsetting is installed rather
than on-the-fly.
For now, the change to the ehci_iso_stream lifetimes means that each
structure is always deallocated at exactly one spot in
ehci_endpoint_disable() and never used again. As a result, it is no
longer necessary to use reference counting on these things, and the
patch removes it.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 12 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 53 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 3 |
3 files changed, 16 insertions, 52 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 98b945840c9e..fb1966cf5649 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -1085,8 +1085,14 @@ rescan: | |||
1085 | * accelerate iso completions ... so spin a while. | 1085 | * accelerate iso completions ... so spin a while. |
1086 | */ | 1086 | */ |
1087 | if (qh->hw == NULL) { | 1087 | if (qh->hw == NULL) { |
1088 | ehci_vdbg (ehci, "iso delay\n"); | 1088 | struct ehci_iso_stream *stream = ep->hcpriv; |
1089 | goto idle_timeout; | 1089 | |
1090 | if (!list_empty(&stream->td_list)) | ||
1091 | goto idle_timeout; | ||
1092 | |||
1093 | /* BUG_ON(!list_empty(&stream->free_list)); */ | ||
1094 | kfree(stream); | ||
1095 | goto done; | ||
1090 | } | 1096 | } |
1091 | 1097 | ||
1092 | if (ehci->rh_state < EHCI_RH_RUNNING) | 1098 | if (ehci->rh_state < EHCI_RH_RUNNING) |
@@ -1127,8 +1133,8 @@ idle_timeout: | |||
1127 | list_empty (&qh->qtd_list) ? "" : "(has tds)"); | 1133 | list_empty (&qh->qtd_list) ? "" : "(has tds)"); |
1128 | break; | 1134 | break; |
1129 | } | 1135 | } |
1136 | done: | ||
1130 | ep->hcpriv = NULL; | 1137 | ep->hcpriv = NULL; |
1131 | done: | ||
1132 | spin_unlock_irqrestore (&ehci->lock, flags); | 1138 | spin_unlock_irqrestore (&ehci->lock, flags); |
1133 | } | 1139 | } |
1134 | 1140 | ||
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 1e4f13c11b6a..11b2f21d7ac1 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -934,7 +934,6 @@ iso_stream_alloc (gfp_t mem_flags) | |||
934 | INIT_LIST_HEAD(&stream->td_list); | 934 | INIT_LIST_HEAD(&stream->td_list); |
935 | INIT_LIST_HEAD(&stream->free_list); | 935 | INIT_LIST_HEAD(&stream->free_list); |
936 | stream->next_uframe = -1; | 936 | stream->next_uframe = -1; |
937 | stream->refcount = 1; | ||
938 | } | 937 | } |
939 | return stream; | 938 | return stream; |
940 | } | 939 | } |
@@ -1034,32 +1033,6 @@ iso_stream_init ( | |||
1034 | stream->maxp = maxp; | 1033 | stream->maxp = maxp; |
1035 | } | 1034 | } |
1036 | 1035 | ||
1037 | static void | ||
1038 | iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) | ||
1039 | { | ||
1040 | stream->refcount--; | ||
1041 | |||
1042 | /* free whenever just a dev->ep reference remains. | ||
1043 | * not like a QH -- no persistent state (toggle, halt) | ||
1044 | */ | ||
1045 | if (stream->refcount == 1) { | ||
1046 | // BUG_ON (!list_empty(&stream->td_list)); | ||
1047 | |||
1048 | if (stream->ep) | ||
1049 | stream->ep->hcpriv = NULL; | ||
1050 | |||
1051 | kfree(stream); | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | static inline struct ehci_iso_stream * | ||
1056 | iso_stream_get (struct ehci_iso_stream *stream) | ||
1057 | { | ||
1058 | if (likely (stream != NULL)) | ||
1059 | stream->refcount++; | ||
1060 | return stream; | ||
1061 | } | ||
1062 | |||
1063 | static struct ehci_iso_stream * | 1036 | static struct ehci_iso_stream * |
1064 | iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) | 1037 | iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) |
1065 | { | 1038 | { |
@@ -1080,7 +1053,6 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) | |||
1080 | if (unlikely (stream == NULL)) { | 1053 | if (unlikely (stream == NULL)) { |
1081 | stream = iso_stream_alloc(GFP_ATOMIC); | 1054 | stream = iso_stream_alloc(GFP_ATOMIC); |
1082 | if (likely (stream != NULL)) { | 1055 | if (likely (stream != NULL)) { |
1083 | /* dev->ep owns the initial refcount */ | ||
1084 | ep->hcpriv = stream; | 1056 | ep->hcpriv = stream; |
1085 | stream->ep = ep; | 1057 | stream->ep = ep; |
1086 | iso_stream_init(ehci, stream, urb->dev, urb->pipe, | 1058 | iso_stream_init(ehci, stream, urb->dev, urb->pipe, |
@@ -1095,9 +1067,6 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) | |||
1095 | stream = NULL; | 1067 | stream = NULL; |
1096 | } | 1068 | } |
1097 | 1069 | ||
1098 | /* caller guarantees an eventual matching iso_stream_put */ | ||
1099 | stream = iso_stream_get (stream); | ||
1100 | |||
1101 | spin_unlock_irqrestore (&ehci->lock, flags); | 1070 | spin_unlock_irqrestore (&ehci->lock, flags); |
1102 | return stream; | 1071 | return stream; |
1103 | } | 1072 | } |
@@ -1611,7 +1580,7 @@ static void itd_link_urb( | |||
1611 | itd = list_entry (iso_sched->td_list.next, | 1580 | itd = list_entry (iso_sched->td_list.next, |
1612 | struct ehci_itd, itd_list); | 1581 | struct ehci_itd, itd_list); |
1613 | list_move_tail (&itd->itd_list, &stream->td_list); | 1582 | list_move_tail (&itd->itd_list, &stream->td_list); |
1614 | itd->stream = iso_stream_get (stream); | 1583 | itd->stream = stream; |
1615 | itd->urb = urb; | 1584 | itd->urb = urb; |
1616 | itd_init (ehci, stream, itd); | 1585 | itd_init (ehci, stream, itd); |
1617 | } | 1586 | } |
@@ -1735,7 +1704,6 @@ itd_complete ( | |||
1735 | dev->devpath, stream->bEndpointAddress & 0x0f, | 1704 | dev->devpath, stream->bEndpointAddress & 0x0f, |
1736 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); | 1705 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); |
1737 | } | 1706 | } |
1738 | iso_stream_put (ehci, stream); | ||
1739 | 1707 | ||
1740 | done: | 1708 | done: |
1741 | itd->urb = NULL; | 1709 | itd->urb = NULL; |
@@ -1750,7 +1718,6 @@ done: | |||
1750 | start_free_itds(ehci); | 1718 | start_free_itds(ehci); |
1751 | } | 1719 | } |
1752 | 1720 | ||
1753 | iso_stream_put(ehci, stream); | ||
1754 | return retval; | 1721 | return retval; |
1755 | } | 1722 | } |
1756 | 1723 | ||
@@ -1807,12 +1774,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, | |||
1807 | itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); | 1774 | itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); |
1808 | else | 1775 | else |
1809 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); | 1776 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); |
1810 | done_not_linked: | 1777 | done_not_linked: |
1811 | spin_unlock_irqrestore (&ehci->lock, flags); | 1778 | spin_unlock_irqrestore (&ehci->lock, flags); |
1812 | 1779 | done: | |
1813 | done: | ||
1814 | if (unlikely (status < 0)) | ||
1815 | iso_stream_put (ehci, stream); | ||
1816 | return status; | 1780 | return status; |
1817 | } | 1781 | } |
1818 | 1782 | ||
@@ -2028,7 +1992,7 @@ static void sitd_link_urb( | |||
2028 | sitd = list_entry (sched->td_list.next, | 1992 | sitd = list_entry (sched->td_list.next, |
2029 | struct ehci_sitd, sitd_list); | 1993 | struct ehci_sitd, sitd_list); |
2030 | list_move_tail (&sitd->sitd_list, &stream->td_list); | 1994 | list_move_tail (&sitd->sitd_list, &stream->td_list); |
2031 | sitd->stream = iso_stream_get (stream); | 1995 | sitd->stream = stream; |
2032 | sitd->urb = urb; | 1996 | sitd->urb = urb; |
2033 | 1997 | ||
2034 | sitd_patch(ehci, stream, sitd, sched, packet); | 1998 | sitd_patch(ehci, stream, sitd, sched, packet); |
@@ -2126,7 +2090,6 @@ sitd_complete ( | |||
2126 | dev->devpath, stream->bEndpointAddress & 0x0f, | 2090 | dev->devpath, stream->bEndpointAddress & 0x0f, |
2127 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); | 2091 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); |
2128 | } | 2092 | } |
2129 | iso_stream_put (ehci, stream); | ||
2130 | 2093 | ||
2131 | done: | 2094 | done: |
2132 | sitd->urb = NULL; | 2095 | sitd->urb = NULL; |
@@ -2141,7 +2104,6 @@ done: | |||
2141 | start_free_itds(ehci); | 2104 | start_free_itds(ehci); |
2142 | } | 2105 | } |
2143 | 2106 | ||
2144 | iso_stream_put(ehci, stream); | ||
2145 | return retval; | 2107 | return retval; |
2146 | } | 2108 | } |
2147 | 2109 | ||
@@ -2195,12 +2157,9 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, | |||
2195 | sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); | 2157 | sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); |
2196 | else | 2158 | else |
2197 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); | 2159 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); |
2198 | done_not_linked: | 2160 | done_not_linked: |
2199 | spin_unlock_irqrestore (&ehci->lock, flags); | 2161 | spin_unlock_irqrestore (&ehci->lock, flags); |
2200 | 2162 | done: | |
2201 | done: | ||
2202 | if (status < 0) | ||
2203 | iso_stream_put (ehci, stream); | ||
2204 | return status; | 2163 | return status; |
2205 | } | 2164 | } |
2206 | 2165 | ||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bcfbb175e2b4..755e30b0000b 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -386,7 +386,7 @@ struct ehci_qh_hw { | |||
386 | } __attribute__ ((aligned(32))); | 386 | } __attribute__ ((aligned(32))); |
387 | 387 | ||
388 | struct ehci_qh { | 388 | struct ehci_qh { |
389 | struct ehci_qh_hw *hw; | 389 | struct ehci_qh_hw *hw; /* Must come first */ |
390 | /* the rest is HCD-private */ | 390 | /* the rest is HCD-private */ |
391 | dma_addr_t qh_dma; /* address of qh */ | 391 | dma_addr_t qh_dma; /* address of qh */ |
392 | union ehci_shadow qh_next; /* ptr to qh; or periodic */ | 392 | union ehci_shadow qh_next; /* ptr to qh; or periodic */ |
@@ -453,7 +453,6 @@ struct ehci_iso_stream { | |||
453 | /* first field matches ehci_hq, but is NULL */ | 453 | /* first field matches ehci_hq, but is NULL */ |
454 | struct ehci_qh_hw *hw; | 454 | struct ehci_qh_hw *hw; |
455 | 455 | ||
456 | u32 refcount; | ||
457 | u8 bEndpointAddress; | 456 | u8 bEndpointAddress; |
458 | u8 highspeed; | 457 | u8 highspeed; |
459 | struct list_head td_list; /* queued itds/sitds */ | 458 | struct list_head td_list; /* queued itds/sitds */ |