Commit 8c339122 authored by David Brownell's avatar David Brownell Committed by Doug Ledford

[PATCH] usb problems (ohci-hcd + printer)

This fixes a number of issues in OHCI:

 - Force out the PCI write disabling control/bulk queues.
   This "shouldn't" matter, they're empty.

 - The rule is that if an ED is IDLE, its OK to just
   schedule it and start appending TDs.  Hard to do that
   when the typical error path left them still halted!

 - Sometimes ed->hwTailP needs updating when TDs are
   removed from the queue, not just ed->hwHeadP. Oops.

 - Oh, and it's not the high bits we want to save when
   we unlink ... it's the low bits (actually just toggle).

Except for forcing the writes to the controller, these patches should
only affect (improve :) fault and unlink handling.
parent 1e1af316
...@@ -265,6 +265,9 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) ...@@ -265,6 +265,9 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
if (!ed->hwNextED) { if (!ed->hwNextED) {
ohci->hc_control &= ~OHCI_CTRL_CLE; ohci->hc_control &= ~OHCI_CTRL_CLE;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
writel (0, &ohci->regs->ed_controlcurrent);
// post those pci writes
(void) readl (&ohci->regs->control);
} }
writel (le32_to_cpup (&ed->hwNextED), writel (le32_to_cpup (&ed->hwNextED),
&ohci->regs->ed_controlhead); &ohci->regs->ed_controlhead);
...@@ -286,6 +289,9 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) ...@@ -286,6 +289,9 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
if (!ed->hwNextED) { if (!ed->hwNextED) {
ohci->hc_control &= ~OHCI_CTRL_BLE; ohci->hc_control &= ~OHCI_CTRL_BLE;
writel (ohci->hc_control, &ohci->regs->control); writel (ohci->hc_control, &ohci->regs->control);
writel (0, &ohci->regs->ed_bulkcurrent);
// post those pci writes
(void) readl (&ohci->regs->control);
} }
writel (le32_to_cpup (&ed->hwNextED), writel (le32_to_cpup (&ed->hwNextED),
&ohci->regs->ed_bulkhead); &ohci->regs->ed_bulkhead);
...@@ -315,8 +321,12 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) ...@@ -315,8 +321,12 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
* involves not marking it ED_IDLE till INTR_SF; we always do that * involves not marking it ED_IDLE till INTR_SF; we always do that
* if td_list isn't empty. Otherwise the race is small; but ... * if td_list isn't empty. Otherwise the race is small; but ...
*/ */
if (ed->state == ED_OPER) if (ed->state == ED_OPER) {
ed->state = ED_IDLE; ed->state = ED_IDLE;
ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE);
ed->hwHeadP &= ~ED_H;
wmb ();
}
} }
...@@ -767,6 +777,8 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) ...@@ -767,6 +777,8 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
next->next_dl_td = rev; next->next_dl_td = rev;
rev = next; rev = next;
if (ed->hwTailP == cpu_to_le32 (next->td_dma))
ed->hwTailP = next->hwNextTD;
ed->hwHeadP = next->hwNextTD | toggle; ed->hwHeadP = next->hwNextTD | toggle;
} }
...@@ -881,8 +893,13 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick) ...@@ -881,8 +893,13 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick)
continue; continue;
} }
/* patch pointer hc uses */ /* patch pointers hc uses ... tail, if we're removing
savebits = *prev & cpu_to_le32 (TD_MASK); * an otherwise active td, and whatever td pointer
* points to this td
*/
if (ed->hwTailP == cpu_to_le32 (td->td_dma))
ed->hwTailP = td->hwNextTD;
savebits = *prev & ~cpu_to_le32 (TD_MASK);
*prev = td->hwNextTD | savebits; *prev = td->hwNextTD | savebits;
/* HC may have partly processed this TD */ /* HC may have partly processed this TD */
......
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