Greg, Can you take this patch for 2.6.31, please. David -- David Vrabel, Senior Software Engineer, Drivers CSR, Churchill House, Cambridge Business Park, Tel: +44 (0)1223 692562 Cowley Road, Cambridge, CB4 0WZ http://www.csr.com/
usb: whci-hcd: make endpoint_reset method async usb_hcd_endpoint_reset() may be called in atomic context and must not sleep. So make whci-hcd's endpoint_reset() asynchronous. URBs submitted while the reset is in progress will be queued (on the std list) and transfers will resume once the reset is complete. Signed-off-by: David Vrabel <david.vrabel@xxxxxxx> --- drivers/usb/host/whci/asl.c | 12 +++++++++++- drivers/usb/host/whci/hcd.c | 8 ++++++-- drivers/usb/host/whci/pzl.c | 12 +++++++++++- drivers/usb/host/whci/qset.c | 4 +1+-- drivers/usb/host/whci/whci-hc.h | 1 + 5 files changed, 31 insertions(+), 6 deletions(-) diff -urN a/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/asl.c b/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/asl.c --- a/drivers/usb/host/whci/asl.c 2009-06-24 18:18:12.000000000 +0100 +++ b/drivers/usb/host/whci/asl.c 2009-06-24 18:18:12.000000000 +0100 @@ -231,11 +231,21 @@ /* * Now that the ASL is updated, complete the removal of any * removed qsets. + * + * If the qset was to be reset, do so and reinsert it into the + * ASL if it has pending transfers. */ spin_lock_irq(&whc->lock); list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { qset_remove_complete(whc, qset); + if (qset->reset) { + qset_reset(whc, qset); + if (!list_empty(&qset->stds)) { + asl_qset_insert_begin(whc, qset); + queue_work(whc->workqueue, &whc->async_work); + } + } } spin_unlock_irq(&whc->lock); @@ -271,7 +281,7 @@ else err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); if (!err) { - if (!qset->in_sw_list) + if (!qset->in_sw_list && !qset->remove) asl_qset_insert_begin(whc, qset); } else usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); diff -urN a/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/hcd.c b/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/hcd.c --- a/drivers/usb/host/whci/hcd.c 2009-06-24 18:18:12.000000000 +0100 +++ b/drivers/usb/host/whci/hcd.c 2009-06-24 18:18:12.000000000 +0100 @@ -193,19 +193,23 @@ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct whc *whc = wusbhc_to_whc(wusbhc); struct whc_qset *qset; + unsigned long flags; + + spin_lock_irqsave(&whc->lock, flags); qset = ep->hcpriv; if (qset) { qset->remove = 1; + qset->reset = 1; if (usb_endpoint_xfer_bulk(&ep->desc) || usb_endpoint_xfer_control(&ep->desc)) queue_work(whc->workqueue, &whc->async_work); else queue_work(whc->workqueue, &whc->periodic_work); - - qset_reset(whc, qset); } + + spin_unlock_irqrestore(&whc->lock, flags); } diff -urN a/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/pzl.c b/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/pzl.c --- a/drivers/usb/host/whci/pzl.c 2009-06-24 18:18:12.000000000 +0100 +++ b/drivers/usb/host/whci/pzl.c 2009-06-24 18:18:12.000000000 +0100 @@ -259,11 +259,21 @@ /* * Now that the PZL is updated, complete the removal of any * removed qsets. + * + * If the qset was to be reset, do so and reinsert it into the + * PZL if it has pending transfers. */ spin_lock_irq(&whc->lock); list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { qset_remove_complete(whc, qset); + if (qset->reset) { + qset_reset(whc, qset); + if (!list_empty(&qset->stds)) { + qset_insert_in_sw_list(whc, qset); + queue_work(whc->workqueue, &whc->periodic_work); + } + } } spin_unlock_irq(&whc->lock); @@ -299,7 +309,7 @@ else err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); if (!err) { - if (!qset->in_sw_list) + if (!qset->in_sw_list && !qset->remove) qset_insert_in_sw_list(whc, qset); } else usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); diff -urN a/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/qset.c b/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/qset.c --- a/drivers/usb/host/whci/qset.c 2009-06-24 18:18:12.000000000 +0100 +++ b/drivers/usb/host/whci/qset.c 2009-06-24 18:18:12.000000000 +0100 @@ -122,7 +122,6 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) { qset->td_start = qset->td_end = qset->ntds = 0; - qset->remove = 0; qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; @@ -144,7 +143,7 @@ */ void qset_reset(struct whc *whc, struct whc_qset *qset) { - wait_for_completion(&qset->remove_complete); + qset->reset = 0; qset->qh.status &= ~QH_STATUS_SEQ_MASK; qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); @@ -175,6 +174,7 @@ void qset_remove_complete(struct whc *whc, struct whc_qset *qset) { + qset->remove = 0; list_del_init(&qset->list_node); complete(&qset->remove_complete); } diff -urN a/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/whci-hc.h b/depot/uwb/main/drivers/linux-uwb/main/drivers/usb/host/whci/whci-hc.h --- a/drivers/usb/host/whci/whci-hc.h 2009-06-24 18:18:13.000000000 +0100 +++ b/drivers/usb/host/whci/whci-hc.h 2009-06-24 18:18:13.000000000 +0100 @@ -257,6 +257,7 @@ unsigned in_sw_list:1; unsigned in_hw_list:1; unsigned remove:1; + unsigned reset:1; struct urb *pause_after_urb; struct completion remove_complete; uint16_t max_packet;