Skip to content

Commit

Permalink
USB: isp1760: urb_dequeue doesn't always find the urbs
Browse files Browse the repository at this point in the history
The option driver (and presumably others) allocates several URBs when it
opens and tries to free them when it closes. The isp1760_urb_dequeue
function gets called, but the packet being dequeued is not necessarily at
the
front of one of the 32 queues. If not, the isp1760_urb_done function doesn't
get called for the URB and the process trying to free it hangs forever on a
wait_queue. This patch does two things. If the URB being dequeued has others
queued behind it, it re-queues them. And it searches the queues looking for
the URB being dequeued rather than just looking at the one at the front of
the queue.

[bigeasy@linutronix] whitespace fixes, reformating

Cc: stable <stable@kernel.org>
Signed-off-by: Warren Free <wfree@ipmn.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Warren Free authored and Greg Kroah-Hartman committed May 28, 2009
1 parent cab98a0 commit 0afb20e
Showing 1 changed file with 22 additions and 2 deletions.
24 changes: 22 additions & 2 deletions drivers/usb/host/isp1760-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
u32 reg_base, or_reg, skip_reg;
unsigned long flags;
struct ptd ptd;
packet_enqueue *pe;

switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
Expand All @@ -1669,13 +1670,15 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
reg_base = INT_REGS_OFFSET;
or_reg = HC_INT_IRQ_MASK_OR_REG;
skip_reg = HC_INT_PTD_SKIPMAP_REG;
pe = enqueue_an_INT_packet;
break;

default:
ints = priv->atl_ints;
reg_base = ATL_REGS_OFFSET;
or_reg = HC_ATL_IRQ_MASK_OR_REG;
skip_reg = HC_ATL_PTD_SKIPMAP_REG;
pe = enqueue_an_ATL_packet;
break;
}

Expand All @@ -1687,6 +1690,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
u32 skip_map;
u32 or_map;
struct isp1760_qtd *qtd;
struct isp1760_qh *qh = ints->qh;

skip_map = isp1760_readl(hcd->regs + skip_reg);
skip_map |= 1 << i;
Expand All @@ -1699,8 +1703,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base
+ i * sizeof(ptd), sizeof(ptd));
qtd = ints->qtd;

clean_up_qtdlist(qtd);
qtd = clean_up_qtdlist(qtd);

free_mem(priv, ints->payload);

Expand All @@ -1711,7 +1714,24 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
ints->payload = 0;

isp1760_urb_done(priv, urb, status);
if (qtd)
pe(hcd, qh, qtd);
break;

} else if (ints->qtd) {
struct isp1760_qtd *qtd, *prev_qtd = ints->qtd;

for (qtd = ints->qtd->hw_next; qtd; qtd = qtd->hw_next) {
if (qtd->urb == urb) {
prev_qtd->hw_next = clean_up_qtdlist(qtd);
isp1760_urb_done(priv, urb, status);
break;
}
prev_qtd = qtd;
}
/* we found the urb before the end of the list */
if (qtd)
break;
}
ints++;
}
Expand Down

0 comments on commit 0afb20e

Please sign in to comment.