static int ohci_bus_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { spin_unlock_irqrestore (&ohci->lock, flags); return -ESHUTDOWN; } ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_RESUME: ohci_dbg (ohci, "resume/suspend?\n"); ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_RESET; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* FALL THROUGH */ case OHCI_USB_RESET: status = -EBUSY; ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: ohci_dbg (ohci, "already suspended\n"); goto done; } ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; ohci->hc_control &= ~OHCI_SCHED_ENABLES; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); /* sched disables take effect on the next frame, * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); limit = 2000; while (limit > 0) { udelay (250); limit =- 250; if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_SF) break; } dl_done_list (ohci, NULL); mdelay (7); } dl_done_list (ohci, NULL); finish_unlinks (ohci, ohci_frame_no(ohci), NULL); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) ohci->hc_control |= OHCI_CTRL_RWE; else ohci->hc_control &= ~OHCI_CTRL_RWE; /* Suspend hub ... this is the "global (to this bus) suspend" mode, * which doesn't imply ports will first be individually suspended. */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); /* no timer polling */ hcd->poll_rh = 0; done: /* external suspend vs self autosuspend ... same effect */ if (status == 0) usb_hcd_suspend_root_hub(hcd); spin_unlock_irqrestore (&ohci->lock, flags); return status; }
static int ohci_hub_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; unsigned long flags; #ifndef USB_FREE_IRQ_AT_SUSPEND_MODE #if defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) return 0; #endif /* defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) */ #endif /* USB_FREE_IRQ_AT_SUSPEND_MODE */ spin_lock_irqsave (&ohci->lock, flags); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_RESUME: ohci_dbg (ohci, "resume/suspend?\n"); ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_RESET; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* FALL THROUGH */ case OHCI_USB_RESET: status = -EBUSY; ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: ohci_dbg (ohci, "already suspended\n"); goto done; } ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ hcd->state = HC_STATE_QUIESCING; if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; ohci->hc_control &= ~OHCI_SCHED_ENABLES; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); /* sched disables take effect on the next frame, * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); limit = 2000; while (limit > 0) { udelay (250); limit =- 250; if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_SF) break; } dl_done_list (ohci, NULL); mdelay (7); } dl_done_list (ohci, NULL); finish_unlinks (ohci, ohci_frame_no(ohci), NULL); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ if (hcd->remote_wakeup) ohci->hc_control |= OHCI_CTRL_RWE; else ohci->hc_control &= ~OHCI_CTRL_RWE; /* Suspend hub */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); done: if (status == 0) hcd->state = HC_STATE_SUSPENDED; spin_unlock_irqrestore (&ohci->lock, flags); return status; }
static void admhc_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct admhcd *ahcd = hcd_to_admhcd(hcd); unsigned long flags; struct ed *ed = ep->hcpriv; unsigned limit = 1000; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ if (!ed) return; #ifdef ADMHC_VERBOSE_DEBUG spin_lock_irqsave(&ahcd->lock, flags); admhc_dump_ed(ahcd, "EP-DISABLE", ed, 1); spin_unlock_irqrestore(&ahcd->lock, flags); #endif rescan: spin_lock_irqsave(&ahcd->lock, flags); if (!HC_IS_RUNNING(hcd->state)) { sanitize: ed->state = ED_IDLE; finish_unlinks(ahcd, 0); } switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SOFI too... */ if (limit-- == 0) { admhc_warn(ahcd, "IRQ INTR_SOFI lossage\n"); goto sanitize; } spin_unlock_irqrestore(&ahcd->lock, flags); schedule_timeout_uninterruptible(1); goto rescan; case ED_IDLE: /* fully unlinked */ if (list_empty(&ed->td_list)) { td_free (ahcd, ed->dummy); ed_free (ahcd, ed); break; } /* else FALL THROUGH */ default: /* caller was supposed to have unlinked any requests; * that's not our job. can't recover; must leak ed. */ admhc_err(ahcd, "leak ed %p (#%02x) state %d%s\n", ed, ep->desc.bEndpointAddress, ed->state, list_empty(&ed->td_list) ? "" : " (has tds)"); td_free(ahcd, ed->dummy); break; } ep->hcpriv = NULL; spin_unlock_irqrestore(&ahcd->lock, flags); return; }
static irqreturn_t admhc_irq(struct usb_hcd *hcd) { struct admhcd *ahcd = hcd_to_admhcd(hcd); struct admhcd_regs __iomem *regs = ahcd->regs; u32 ints; ints = admhc_readl(ahcd, ®s->int_status); if ((ints & ADMHC_INTR_INTA) == 0) { /* no unmasked interrupt status is set */ return IRQ_NONE; } ints &= admhc_readl(ahcd, ®s->int_enable); if (ints & ADMHC_INTR_FATI) { /* e.g. due to PCI Master/Target Abort */ admhc_disable(ahcd); admhc_err(ahcd, "Fatal Error, controller disabled\n"); admhc_dump(ahcd, 1); admhc_usb_reset(ahcd); } if (ints & ADMHC_INTR_BABI) { admhc_intr_disable(ahcd, ADMHC_INTR_BABI); admhc_intr_ack(ahcd, ADMHC_INTR_BABI); admhc_err(ahcd, "Babble Detected\n"); } if (ints & ADMHC_INTR_INSM) { admhc_vdbg(ahcd, "Root Hub Status Change\n"); ahcd->next_statechange = jiffies + STATECHANGE_DELAY; admhc_intr_ack(ahcd, ADMHC_INTR_RESI | ADMHC_INTR_INSM); /* NOTE: Vendors didn't always make the same implementation * choices for RHSC. Many followed the spec; RHSC triggers * on an edge, like setting and maybe clearing a port status * change bit. With others it's level-triggered, active * until khubd clears all the port status change bits. We'll * always disable it here and rely on polling until khubd * re-enables it. */ admhc_intr_disable(ahcd, ADMHC_INTR_INSM); usb_hcd_poll_rh_status(hcd); } else if (ints & ADMHC_INTR_RESI) { /* For connect and disconnect events, we expect the controller * to turn on RHSC along with RD. But for remote wakeup events * this might not happen. */ admhc_vdbg(ahcd, "Resume Detect\n"); admhc_intr_ack(ahcd, ADMHC_INTR_RESI); hcd->poll_rh = 1; if (ahcd->autostop) { spin_lock(&ahcd->lock); admhc_rh_resume(ahcd); spin_unlock(&ahcd->lock); } else usb_hcd_resume_root_hub(hcd); } if (ints & ADMHC_INTR_TDC) { admhc_vdbg(ahcd, "Transfer Descriptor Complete\n"); admhc_intr_ack(ahcd, ADMHC_INTR_TDC); if (HC_IS_RUNNING(hcd->state)) admhc_intr_disable(ahcd, ADMHC_INTR_TDC); spin_lock(&ahcd->lock); admhc_td_complete(ahcd); spin_unlock(&ahcd->lock); if (HC_IS_RUNNING(hcd->state)) admhc_intr_enable(ahcd, ADMHC_INTR_TDC); } if (ints & ADMHC_INTR_SO) { /* could track INTR_SO to reduce available PCI/... bandwidth */ admhc_vdbg(ahcd, "Schedule Overrun\n"); } #if 1 spin_lock(&ahcd->lock); if (ahcd->ed_rm_list) finish_unlinks(ahcd, admhc_frame_no(ahcd)); if ((ints & ADMHC_INTR_SOFI) != 0 && !ahcd->ed_rm_list && HC_IS_RUNNING(hcd->state)) admhc_intr_disable(ahcd, ADMHC_INTR_SOFI); spin_unlock(&ahcd->lock); #else if (ints & ADMHC_INTR_SOFI) { admhc_vdbg(ahcd, "Start Of Frame\n"); spin_lock(&ahcd->lock); /* handle any pending ED removes */ finish_unlinks(ahcd, admhc_frameno(ahcd)); /* leaving INTR_SOFI enabled when there's still unlinking * to be done in the (next frame). */ if ((ahcd->ed_rm_list == NULL) || HC_IS_RUNNING(hcd->state) == 0) /* * disable INTR_SOFI if there are no unlinking to be * done (in the next frame) */ admhc_intr_disable(ahcd, ADMHC_INTR_SOFI); spin_unlock(&ahcd->lock); } #endif if (HC_IS_RUNNING(hcd->state)) { admhc_intr_ack(ahcd, ints); admhc_intr_enable(ahcd, ADMHC_INTR_MIE); admhc_writel_flush(ahcd); } return IRQ_HANDLED; }
static int ohci_hub_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub; int status = 0; if (root->dev.power.power_state != 0) return 0; if (time_before (jiffies, ohci->next_statechange)) return -EAGAIN; spin_lock_irq (&ohci->lock); ohci->hc_control = ohci_readl (&ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_RESUME: ohci_dbg (ohci, "resume/suspend?\n"); ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_RESET; writel (ohci->hc_control, &ohci->regs->control); (void) ohci_readl (&ohci->regs->control); /* FALL THROUGH */ case OHCI_USB_RESET: status = -EBUSY; ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: ohci_dbg (ohci, "already suspended?\n"); goto succeed; } ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ ohci->hcd.state = USB_STATE_QUIESCING; if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; ohci->hc_control &= ~OHCI_SCHED_ENABLES; writel (ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (&ohci->regs->control); writel (OHCI_INTR_SF, &ohci->regs->intrstatus); /* sched disables take effect on the next frame, * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); limit = 2000; while (limit > 0) { udelay (250); limit =- 250; if (ohci_readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) break; } dl_done_list (ohci, NULL); mdelay (7); } dl_done_list (ohci, NULL); finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca), NULL); writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ if (ohci->hcd.remote_wakeup) ohci->hc_control |= OHCI_CTRL_RWE; else ohci->hc_control &= ~OHCI_CTRL_RWE; /* Suspend hub */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; writel (ohci->hc_control, &ohci->regs->control); (void) ohci_readl (&ohci->regs->control); /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); succeed: /* it's not USB_STATE_SUSPENDED unless access to this * hub from the non-usb side (PCI, SOC, etc) stopped */ root->dev.power.power_state = 3; done: spin_unlock_irq (&ohci->lock); return status; }