summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2012-03-05 17:49:40 +0800
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-03-13 09:30:44 -0700
commit085deb16845ee0b25385274b39c70cc07e6e4140 (patch)
tree7e08185fde1567ba14095f4bebe7a9c5c7fd1d36 /drivers/usb
parent2fdcd47b6980f4e26a97811a17f5be7cb919ef90 (diff)
downloadlinux-085deb16845ee0b25385274b39c70cc07e6e4140.tar.gz
linux-085deb16845ee0b25385274b39c70cc07e6e4140.tar.bz2
linux-085deb16845ee0b25385274b39c70cc07e6e4140.zip
xHCI: check enqueue pointer advance into dequeue seg
When a urb is submitted to xHCI driver, check if queueing the urb will make the enqueue pointer advance into dequeue seg and expand the ring if it occurs. This is to guarantee the safety of ring expansion. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Tested-by: Paul Zimmerman <Paul.Zimmerman@synopsys.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-ring.c25
1 files changed, 13 insertions, 12 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 4194f348e3a7..6bd9d53062eb 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -249,16 +249,24 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
}
/*
- * Check to see if there's room to enqueue num_trbs on the ring. See rules
- * above.
+ * Check to see if there's room to enqueue num_trbs on the ring and make sure
+ * enqueue pointer will not advance into dequeue segment. See rules above.
*/
static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs)
{
- if (ring->num_trbs_free >= num_trbs)
- return 1;
+ int num_trbs_in_deq_seg;
- return 0;
+ if (ring->num_trbs_free < num_trbs)
+ return 0;
+
+ if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
+ num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
+ if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
+ return 0;
+ }
+
+ return 1;
}
/* Ring the host controller doorbell after placing a command on the ring */
@@ -2529,13 +2537,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
return -ENOMEM;
}
- if (ep_ring->enq_seg == ep_ring->deq_seg &&
- ep_ring->dequeue > ep_ring->enqueue) {
- xhci_err(xhci, "Can not expand the ring while dequeue "
- "pointer has not passed the link TRB\n");
- return -ENOMEM;
- }
-
xhci_dbg(xhci, "ERROR no room on ep ring, "
"try ring expansion\n");
num_trbs_needed = num_trbs - ep_ring->num_trbs_free;