Commit 18a860b2 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: ohci misc updates

Mostly from Benjamin Herrenschmidt:

  - prevent usbcore from asking the HCD root hub code
    to read registers on one more suspend path (some
    hardware gets upset in those cases);

  - try handling a "device died" cleanup case better

  - add some wmb() calls in spots that could matter
    on some hardware
parent dc6b9d7f
...@@ -418,6 +418,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -418,6 +418,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
default: default:
/* non-generic request */ /* non-generic request */
if (HCD_IS_SUSPENDED (hcd->state))
urb->status = -EAGAIN;
else if (!HCD_IS_RUNNING (hcd->state))
urb->status = -ENODEV;
else
urb->status = hcd->driver->hub_control (hcd, urb->status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex, typeReq, wValue, wIndex,
ubuf, wLength); ubuf, wLength);
......
...@@ -344,8 +344,11 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) ...@@ -344,8 +344,11 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
if (!ed) if (!ed)
goto done; goto done;
if (!HCD_IS_RUNNING (ohci->hcd.state)) if (!HCD_IS_RUNNING (ohci->hcd.state)) {
ed->state = ED_IDLE; ed->state = ED_IDLE;
finish_unlinks (ohci, 0, 0);
}
switch (ed->state) { switch (ed->state) {
case ED_UNLINK: /* wait for hw to finish? */ case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */ /* major IRQ delivery trouble loses INTR_SF too... */
......
...@@ -156,6 +156,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) ...@@ -156,6 +156,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
wmb (); wmb ();
*prev = ed; *prev = ed;
*prev_p = cpu_to_le32p (&ed->dma); *prev_p = cpu_to_le32p (&ed->dma);
wmb();
} }
ohci->load [i] += ed->load; ohci->load [i] += ed->load;
} }
...@@ -195,6 +196,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ...@@ -195,6 +196,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
} }
ed->ed_prev = ohci->ed_controltail; ed->ed_prev = ohci->ed_controltail;
if (!ohci->ed_controltail && !ohci->ed_rm_list) { if (!ohci->ed_controltail && !ohci->ed_rm_list) {
wmb();
ohci->hc_control |= OHCI_CTRL_CLE; ohci->hc_control |= OHCI_CTRL_CLE;
writel (0, &ohci->regs->ed_controlcurrent); writel (0, &ohci->regs->ed_controlcurrent);
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
...@@ -212,6 +214,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ...@@ -212,6 +214,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
} }
ed->ed_prev = ohci->ed_bulktail; ed->ed_prev = ohci->ed_bulktail;
if (!ohci->ed_bulktail && !ohci->ed_rm_list) { if (!ohci->ed_bulktail && !ohci->ed_rm_list) {
wmb();
ohci->hc_control |= OHCI_CTRL_BLE; ohci->hc_control |= OHCI_CTRL_BLE;
writel (0, &ohci->regs->ed_bulkcurrent); writel (0, &ohci->regs->ed_bulkcurrent);
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
...@@ -868,6 +871,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -868,6 +871,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
td_dma = le32_to_cpup (&ohci->hcca->done_head); td_dma = le32_to_cpup (&ohci->hcca->done_head);
ohci->hcca->done_head = 0; ohci->hcca->done_head = 0;
wmb();
/* get TD from hc's singly linked list, and /* get TD from hc's singly linked list, and
* prepend to ours. ed->td_list changes later. * prepend to ours. ed->td_list changes later.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment