/* Set a bit in the USBCMD register */ staticvoid ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit)
{
ehci->command |= bit;
ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* Poll again later, but give up after about 2-4 ms */ if (ehci->ASS_poll_count++ < 2) {
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); return;
}
ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n",
want, actual);
}
ehci->ASS_poll_count = 0;
/* The status is up-to-date; restart or stop the schedule as needed */ if (want == 0) { /* Stopped */ if (ehci->async_count > 0)
ehci_set_command_bit(ehci, CMD_ASE);
/* Poll again later, but give up after about 2-4 ms */ if (ehci->PSS_poll_count++ < 2) {
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); return;
}
ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
want, actual);
}
ehci->PSS_poll_count = 0;
/* The status is up-to-date; restart or stop the schedule as needed */ if (want == 0) { /* Stopped */ if (ehci->periodic_count > 0)
ehci_set_command_bit(ehci, CMD_PSE);
/* Turn off the schedule after a while */
ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC, true);
}
}
}
/* Turn off the periodic schedule after a brief delay */ staticvoid ehci_disable_PSE(struct ehci_hcd *ehci)
{
ehci_clear_command_bit(ehci, CMD_PSE);
}
/* Poll the STS_HALT status bit; see when a dead controller stops */ staticvoid ehci_handle_controller_death(struct ehci_hcd *ehci)
{ if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {
/* Give up after a few milliseconds */ if (ehci->died_poll_count++ < 5) { /* Try again later */
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true); return;
}
ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
}
/* Clean up the mess */
ehci->rh_state = EHCI_RH_HALTED;
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
ehci_work(ehci);
end_unlink_async(ehci);
/* Not in process context, so don't try to reset the controller */
}
/* Handle remaining entries later */ if (!list_empty(&ehci->intr_unlink_wait)) {
ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
++ehci->intr_unlink_wait_cycle;
}
}
/* Handle unlinked interrupt QHs once they are gone from the hardware */ staticvoid ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
{ bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
/* Wait for controller to stop using old iTDs and siTDs */ staticvoid end_free_itds(struct ehci_hcd *ehci)
{ struct ehci_itd *itd, *n; struct ehci_sitd *sitd, *sn;
/* If we get here, IAA is *REALLY* late. It's barely *conceivablethatthesystemissobusythatCMD_IAAD *isstilllegitimatelyset,solet'sbesureit's *clearbeforewereadSTS_IAA.(TheHCshouldclear *CMD_IAADwhenitsetsSTS_IAA.)
*/
cmd = ehci_readl(ehci, &ehci->regs->command);
/* Enable the I/O watchdog, if appropriate */ staticvoid turn_on_io_watchdog(struct ehci_hcd *ehci)
{ /* Not needed if the controller isn't running or it's already enabled */ if (ehci->rh_state != EHCI_RH_RUNNING ||
(ehci->enabled_hrtimer_events &
BIT(EHCI_HRTIMER_IO_WATCHDOG))) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.