Merge branch 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus
* 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci: xhci: Handle zero-length isochronous packets. USB: Avoid NULL pointer deref in usb_hcd_alloc_bandwidth. xhci: Remove TDs from TD lists when URBs are canceled. xhci: Fix failed enqueue in the middle of isoch TD. xhci: Fix memory leak during failed enqueue. xHCI: report USB2 port in resuming as suspend xHCI: fix port U3 status check condition
This commit is contained in:
commit
ea8c7fd9b0
4 changed files with 102 additions and 35 deletions
|
@ -1775,6 +1775,8 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
|
|||
struct usb_interface *iface = usb_ifnum_to_if(udev,
|
||||
cur_alt->desc.bInterfaceNumber);
|
||||
|
||||
if (!iface)
|
||||
return -EINVAL;
|
||||
if (iface->resetting_device) {
|
||||
/*
|
||||
* The USB core just reset the device, so the xHCI host
|
||||
|
|
|
@ -463,11 +463,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
&& (temp & PORT_POWER))
|
||||
status |= USB_PORT_STAT_SUSPEND;
|
||||
}
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
|
||||
!DEV_SUPERSPEED(temp)) {
|
||||
if ((temp & PORT_RESET) || !(temp & PORT_PE))
|
||||
goto error;
|
||||
if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
|
||||
bus_state->resume_done[wIndex])) {
|
||||
if (time_after_eq(jiffies,
|
||||
bus_state->resume_done[wIndex])) {
|
||||
xhci_dbg(xhci, "Resume USB2 port %d\n",
|
||||
wIndex + 1);
|
||||
bus_state->resume_done[wIndex] = 0;
|
||||
|
@ -487,6 +488,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
xhci_ring_device(xhci, slot_id);
|
||||
bus_state->port_c_suspend |= 1 << wIndex;
|
||||
bus_state->suspended_ports &= ~(1 << wIndex);
|
||||
} else {
|
||||
/*
|
||||
* The resume has been signaling for less than
|
||||
* 20ms. Report the port status as SUSPEND,
|
||||
* let the usbcore check port status again
|
||||
* and clear resume signaling later.
|
||||
*/
|
||||
status |= USB_PORT_STAT_SUSPEND;
|
||||
}
|
||||
}
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_U0
|
||||
|
@ -664,7 +673,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
xhci_dbg(xhci, "PORTSC %04x\n", temp);
|
||||
if (temp & PORT_RESET)
|
||||
goto error;
|
||||
if (temp & XDEV_U3) {
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_U3) {
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -514,8 +514,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
|
|||
(unsigned long long) addr);
|
||||
}
|
||||
|
||||
/* flip_cycle means flip the cycle bit of all but the first and last TRB.
|
||||
* (The last TRB actually points to the ring enqueue pointer, which is not part
|
||||
* of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
|
||||
*/
|
||||
static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
||||
struct xhci_td *cur_td)
|
||||
struct xhci_td *cur_td, bool flip_cycle)
|
||||
{
|
||||
struct xhci_segment *cur_seg;
|
||||
union xhci_trb *cur_trb;
|
||||
|
@ -528,6 +532,12 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
|||
* leave the pointers intact.
|
||||
*/
|
||||
cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN);
|
||||
/* Flip the cycle bit (link TRBs can't be the first
|
||||
* or last TRB).
|
||||
*/
|
||||
if (flip_cycle)
|
||||
cur_trb->generic.field[3] ^=
|
||||
cpu_to_le32(TRB_CYCLE);
|
||||
xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
|
||||
xhci_dbg(xhci, "Address = %p (0x%llx dma); "
|
||||
"in seg %p (0x%llx dma)\n",
|
||||
|
@ -541,6 +551,11 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
|
|||
cur_trb->generic.field[2] = 0;
|
||||
/* Preserve only the cycle bit of this TRB */
|
||||
cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
|
||||
/* Flip the cycle bit except on the first or last TRB */
|
||||
if (flip_cycle && cur_trb != cur_td->first_trb &&
|
||||
cur_trb != cur_td->last_trb)
|
||||
cur_trb->generic.field[3] ^=
|
||||
cpu_to_le32(TRB_CYCLE);
|
||||
cur_trb->generic.field[3] |= cpu_to_le32(
|
||||
TRB_TYPE(TRB_TR_NOOP));
|
||||
xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
|
||||
|
@ -719,14 +734,14 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
|
|||
cur_td->urb->stream_id,
|
||||
cur_td, &deq_state);
|
||||
else
|
||||
td_to_noop(xhci, ep_ring, cur_td);
|
||||
td_to_noop(xhci, ep_ring, cur_td, false);
|
||||
remove_finished_td:
|
||||
/*
|
||||
* The event handler won't see a completion for this TD anymore,
|
||||
* so remove it from the endpoint ring's TD list. Keep it in
|
||||
* the cancelled TD list for URB completion later.
|
||||
*/
|
||||
list_del(&cur_td->td_list);
|
||||
list_del_init(&cur_td->td_list);
|
||||
}
|
||||
last_unlinked_td = cur_td;
|
||||
xhci_stop_watchdog_timer_in_irq(xhci, ep);
|
||||
|
@ -754,7 +769,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
|
|||
do {
|
||||
cur_td = list_entry(ep->cancelled_td_list.next,
|
||||
struct xhci_td, cancelled_td_list);
|
||||
list_del(&cur_td->cancelled_td_list);
|
||||
list_del_init(&cur_td->cancelled_td_list);
|
||||
|
||||
/* Clean up the cancelled URB */
|
||||
/* Doesn't matter what we pass for status, since the core will
|
||||
|
@ -862,9 +877,9 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
|
|||
cur_td = list_first_entry(&ring->td_list,
|
||||
struct xhci_td,
|
||||
td_list);
|
||||
list_del(&cur_td->td_list);
|
||||
list_del_init(&cur_td->td_list);
|
||||
if (!list_empty(&cur_td->cancelled_td_list))
|
||||
list_del(&cur_td->cancelled_td_list);
|
||||
list_del_init(&cur_td->cancelled_td_list);
|
||||
xhci_giveback_urb_in_irq(xhci, cur_td,
|
||||
-ESHUTDOWN, "killed");
|
||||
}
|
||||
|
@ -873,7 +888,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
|
|||
&temp_ep->cancelled_td_list,
|
||||
struct xhci_td,
|
||||
cancelled_td_list);
|
||||
list_del(&cur_td->cancelled_td_list);
|
||||
list_del_init(&cur_td->cancelled_td_list);
|
||||
xhci_giveback_urb_in_irq(xhci, cur_td,
|
||||
-ESHUTDOWN, "killed");
|
||||
}
|
||||
|
@ -1565,10 +1580,10 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
else
|
||||
*status = 0;
|
||||
}
|
||||
list_del(&td->td_list);
|
||||
list_del_init(&td->td_list);
|
||||
/* Was this TD slated to be cancelled but completed anyway? */
|
||||
if (!list_empty(&td->cancelled_td_list))
|
||||
list_del(&td->cancelled_td_list);
|
||||
list_del_init(&td->cancelled_td_list);
|
||||
|
||||
urb_priv->td_cnt++;
|
||||
/* Giveback the urb when all the tds are completed */
|
||||
|
@ -2500,11 +2515,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,
|
|||
|
||||
if (td_index == 0) {
|
||||
ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb);
|
||||
if (unlikely(ret)) {
|
||||
xhci_urb_free_priv(xhci, urb_priv);
|
||||
urb->hcpriv = NULL;
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
td->urb = urb;
|
||||
|
@ -2672,6 +2684,10 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
|
|||
{
|
||||
int packets_transferred;
|
||||
|
||||
/* One TRB with a zero-length data packet. */
|
||||
if (running_total == 0 && trb_buff_len == 0)
|
||||
return 0;
|
||||
|
||||
/* All the TRB queueing functions don't count the current TRB in
|
||||
* running_total.
|
||||
*/
|
||||
|
@ -3113,21 +3129,16 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
|
|||
struct urb *urb, int i)
|
||||
{
|
||||
int num_trbs = 0;
|
||||
u64 addr, td_len, running_total;
|
||||
u64 addr, td_len;
|
||||
|
||||
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
|
||||
td_len = urb->iso_frame_desc[i].length;
|
||||
|
||||
running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
|
||||
running_total &= TRB_MAX_BUFF_SIZE - 1;
|
||||
if (running_total != 0)
|
||||
num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
|
||||
TRB_MAX_BUFF_SIZE);
|
||||
if (num_trbs == 0)
|
||||
num_trbs++;
|
||||
|
||||
while (running_total < td_len) {
|
||||
num_trbs++;
|
||||
running_total += TRB_MAX_BUFF_SIZE;
|
||||
}
|
||||
|
||||
return num_trbs;
|
||||
}
|
||||
|
||||
|
@ -3226,6 +3237,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
start_trb = &ep_ring->enqueue->generic;
|
||||
start_cycle = ep_ring->cycle_state;
|
||||
|
||||
urb_priv = urb->hcpriv;
|
||||
/* Queue the first TRB, even if it's zero-length */
|
||||
for (i = 0; i < num_tds; i++) {
|
||||
unsigned int total_packet_count;
|
||||
|
@ -3237,9 +3249,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
addr = start_addr + urb->iso_frame_desc[i].offset;
|
||||
td_len = urb->iso_frame_desc[i].length;
|
||||
td_remain_len = td_len;
|
||||
/* FIXME: Ignoring zero-length packets, can those happen? */
|
||||
total_packet_count = roundup(td_len,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
/* A zero-length transfer still involves at least one packet. */
|
||||
if (total_packet_count == 0)
|
||||
total_packet_count++;
|
||||
burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
|
||||
total_packet_count);
|
||||
residue = xhci_get_last_burst_packet_count(xhci,
|
||||
|
@ -3249,12 +3263,13 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
|
||||
urb->stream_id, trbs_per_td, urb, i, mem_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret < 0) {
|
||||
if (i == 0)
|
||||
return ret;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
urb_priv = urb->hcpriv;
|
||||
td = urb_priv->td[i];
|
||||
|
||||
for (j = 0; j < trbs_per_td; j++) {
|
||||
u32 remainder = 0;
|
||||
field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
|
||||
|
@ -3344,6 +3359,27 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
|
||||
start_cycle, start_trb);
|
||||
return 0;
|
||||
cleanup:
|
||||
/* Clean up a partially enqueued isoc transfer. */
|
||||
|
||||
for (i--; i >= 0; i--)
|
||||
list_del_init(&urb_priv->td[i]->td_list);
|
||||
|
||||
/* Use the first TD as a temporary variable to turn the TDs we've queued
|
||||
* into No-ops with a software-owned cycle bit. That way the hardware
|
||||
* won't accidentally start executing bogus TDs when we partially
|
||||
* overwrite them. td->first_trb and td->start_seg are already set.
|
||||
*/
|
||||
urb_priv->td[0]->last_trb = ep_ring->enqueue;
|
||||
/* Every TRB except the first & last will have its cycle bit flipped. */
|
||||
td_to_noop(xhci, ep_ring, urb_priv->td[0], true);
|
||||
|
||||
/* Reset the ring enqueue back to the first TRB and its cycle bit. */
|
||||
ep_ring->enqueue = urb_priv->td[0]->first_trb;
|
||||
ep_ring->enq_seg = urb_priv->td[0]->start_seg;
|
||||
ep_ring->cycle_state = start_cycle;
|
||||
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1085,8 +1085,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|||
if (urb->dev->speed == USB_SPEED_FULL) {
|
||||
ret = xhci_check_maxpacket(xhci, slot_id,
|
||||
ep_index, urb);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
xhci_urb_free_priv(xhci, urb_priv);
|
||||
urb->hcpriv = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have a spinlock and interrupts disabled, so we must pass
|
||||
|
@ -1097,6 +1100,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|||
goto dying;
|
||||
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
|
||||
slot_id, ep_index);
|
||||
if (ret)
|
||||
goto free_priv;
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
@ -1117,6 +1122,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|||
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
|
||||
slot_id, ep_index);
|
||||
}
|
||||
if (ret)
|
||||
goto free_priv;
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
@ -1124,6 +1131,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|||
goto dying;
|
||||
ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
|
||||
slot_id, ep_index);
|
||||
if (ret)
|
||||
goto free_priv;
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
} else {
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
@ -1131,18 +1140,22 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|||
goto dying;
|
||||
ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
|
||||
slot_id, ep_index);
|
||||
if (ret)
|
||||
goto free_priv;
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
}
|
||||
exit:
|
||||
return ret;
|
||||
dying:
|
||||
xhci_urb_free_priv(xhci, urb_priv);
|
||||
urb->hcpriv = NULL;
|
||||
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "
|
||||
"non-responsive xHCI host.\n",
|
||||
urb->ep->desc.bEndpointAddress, urb);
|
||||
ret = -ESHUTDOWN;
|
||||
free_priv:
|
||||
xhci_urb_free_priv(xhci, urb_priv);
|
||||
urb->hcpriv = NULL;
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return -ESHUTDOWN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the right ring for the given URB.
|
||||
|
@ -1239,6 +1252,13 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
|
||||
xhci_dbg(xhci, "HW died, freeing TD.\n");
|
||||
urb_priv = urb->hcpriv;
|
||||
for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
|
||||
td = urb_priv->td[i];
|
||||
if (!list_empty(&td->td_list))
|
||||
list_del_init(&td->td_list);
|
||||
if (!list_empty(&td->cancelled_td_list))
|
||||
list_del_init(&td->cancelled_td_list);
|
||||
}
|
||||
|
||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
|
Loading…
Reference in a new issue