diff options
author | Andiry Xu <andiry.xu@amd.com> | 2010-07-22 18:23:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 17:35:41 -0400 |
commit | 8e51adccd4c4b9ffcd509d7f2afce0a906139f75 (patch) | |
tree | ddd035c4775db7f504878574d3925f5bf4c87ccd /drivers/usb/host/xhci.c | |
parent | d18240db797ed749b511b8dc910c5dcf08be46d6 (diff) |
USB: xHCI: Introduce urb_priv structure
Add urb_priv data structure to xHCI driver. This structure allows multiple
xhci TDs to be linked to one urb, which is essential for isochronous
transfer. For non-isochronous urb, only one TD is needed for one urb;
for isochronous urb, the TD number for the urb is equal to
urb->number_of_packets.
The length field of urb_priv indicates the number of TDs in the urb.
The td_cnt field indicates the number of TDs already processed by xHC.
When td_cnt matches length, the urb can be given back to usbcore.
When an urb is dequeued or cancelled, add all the unprocessed TDs to the
endpoint's cancelled_td_list. When process a cancelled TD, increase
td_cnt field. When td_cnt equals urb_priv->length, giveback the
cancelled urb.
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>
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 45 |
1 files changed, 39 insertions, 6 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3106d22ae053..295a0a2063a6 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -804,7 +804,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) | |||
804 | unsigned long flags; | 804 | unsigned long flags; |
805 | int ret = 0; | 805 | int ret = 0; |
806 | unsigned int slot_id, ep_index; | 806 | unsigned int slot_id, ep_index; |
807 | 807 | struct urb_priv *urb_priv; | |
808 | int size, i; | ||
808 | 809 | ||
809 | if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0) | 810 | if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0) |
810 | return -EINVAL; | 811 | return -EINVAL; |
@@ -824,6 +825,30 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) | |||
824 | ret = -ESHUTDOWN; | 825 | ret = -ESHUTDOWN; |
825 | goto exit; | 826 | goto exit; |
826 | } | 827 | } |
828 | |||
829 | if (usb_endpoint_xfer_isoc(&urb->ep->desc)) | ||
830 | size = urb->number_of_packets; | ||
831 | else | ||
832 | size = 1; | ||
833 | |||
834 | urb_priv = kzalloc(sizeof(struct urb_priv) + | ||
835 | size * sizeof(struct xhci_td *), mem_flags); | ||
836 | if (!urb_priv) | ||
837 | return -ENOMEM; | ||
838 | |||
839 | for (i = 0; i < size; i++) { | ||
840 | urb_priv->td[i] = kzalloc(sizeof(struct xhci_td), mem_flags); | ||
841 | if (!urb_priv->td[i]) { | ||
842 | urb_priv->length = i; | ||
843 | xhci_urb_free_priv(xhci, urb_priv); | ||
844 | return -ENOMEM; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | urb_priv->length = size; | ||
849 | urb_priv->td_cnt = 0; | ||
850 | urb->hcpriv = urb_priv; | ||
851 | |||
827 | if (usb_endpoint_xfer_control(&urb->ep->desc)) { | 852 | if (usb_endpoint_xfer_control(&urb->ep->desc)) { |
828 | /* Check to see if the max packet size for the default control | 853 | /* Check to see if the max packet size for the default control |
829 | * endpoint changed during FS device enumeration | 854 | * endpoint changed during FS device enumeration |
@@ -877,6 +902,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) | |||
877 | exit: | 902 | exit: |
878 | return ret; | 903 | return ret; |
879 | dying: | 904 | dying: |
905 | xhci_urb_free_priv(xhci, urb_priv); | ||
906 | urb->hcpriv = NULL; | ||
880 | xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " | 907 | xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " |
881 | "non-responsive xHCI host.\n", | 908 | "non-responsive xHCI host.\n", |
882 | urb->ep->desc.bEndpointAddress, urb); | 909 | urb->ep->desc.bEndpointAddress, urb); |
@@ -918,9 +945,10 @@ dying: | |||
918 | int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | 945 | int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) |
919 | { | 946 | { |
920 | unsigned long flags; | 947 | unsigned long flags; |
921 | int ret; | 948 | int ret, i; |
922 | u32 temp; | 949 | u32 temp; |
923 | struct xhci_hcd *xhci; | 950 | struct xhci_hcd *xhci; |
951 | struct urb_priv *urb_priv; | ||
924 | struct xhci_td *td; | 952 | struct xhci_td *td; |
925 | unsigned int ep_index; | 953 | unsigned int ep_index; |
926 | struct xhci_ring *ep_ring; | 954 | struct xhci_ring *ep_ring; |
@@ -935,12 +963,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
935 | temp = xhci_readl(xhci, &xhci->op_regs->status); | 963 | temp = xhci_readl(xhci, &xhci->op_regs->status); |
936 | if (temp == 0xffffffff) { | 964 | if (temp == 0xffffffff) { |
937 | xhci_dbg(xhci, "HW died, freeing TD.\n"); | 965 | xhci_dbg(xhci, "HW died, freeing TD.\n"); |
938 | td = (struct xhci_td *) urb->hcpriv; | 966 | urb_priv = urb->hcpriv; |
939 | 967 | ||
940 | usb_hcd_unlink_urb_from_ep(hcd, urb); | 968 | usb_hcd_unlink_urb_from_ep(hcd, urb); |
941 | spin_unlock_irqrestore(&xhci->lock, flags); | 969 | spin_unlock_irqrestore(&xhci->lock, flags); |
942 | usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); | 970 | usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); |
943 | kfree(td); | 971 | xhci_urb_free_priv(xhci, urb_priv); |
944 | return ret; | 972 | return ret; |
945 | } | 973 | } |
946 | if (xhci->xhc_state & XHCI_STATE_DYING) { | 974 | if (xhci->xhc_state & XHCI_STATE_DYING) { |
@@ -968,9 +996,14 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
968 | 996 | ||
969 | xhci_dbg(xhci, "Endpoint ring:\n"); | 997 | xhci_dbg(xhci, "Endpoint ring:\n"); |
970 | xhci_debug_ring(xhci, ep_ring); | 998 | xhci_debug_ring(xhci, ep_ring); |
971 | td = (struct xhci_td *) urb->hcpriv; | ||
972 | 999 | ||
973 | list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); | 1000 | urb_priv = urb->hcpriv; |
1001 | |||
1002 | for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { | ||
1003 | td = urb_priv->td[i]; | ||
1004 | list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); | ||
1005 | } | ||
1006 | |||
974 | /* Queue a stop endpoint command, but only if this is | 1007 | /* Queue a stop endpoint command, but only if this is |
975 | * the first cancellation to be handled. | 1008 | * the first cancellation to be handled. |
976 | */ | 1009 | */ |