/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... * off the controller (maybe it can boot from highspeed USB disks). */ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); /* always say Linux will own the hardware */ pci_write_config_byte(pdev, where + 3, 1); /* maybe wait a while for BIOS to respond */ if (cap & (1 << 16)) { int msec = 5000; do { msleep(10); msec -= 10; pci_read_config_dword(pdev, where, &cap); } while ((cap & (1 << 16)) && msec); if (cap & (1 << 16)) { ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", where, cap); // some BIOS versions seem buggy... // return 1; ehci_warn (ehci, "continuing after BIOS bug...\n"); /* disable all SMIs, and clear "BIOS owns" flag */ pci_write_config_dword(pdev, where + 4, 0); pci_write_config_byte(pdev, where + 2, 0); } else ehci_dbg(ehci, "BIOS handoff succeeded\n"); } return 0; }
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... * off the controller (maybe it can boot from highspeed USB disks). */ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { if (cap & (1 << 16)) { int msec = 5000; struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); /* request handoff to OS */ cap |= 1 << 24; pci_write_config_dword(pdev, where, cap); /* and wait a while for it to happen */ do { msleep(10); msec -= 10; pci_read_config_dword(pdev, where, &cap); } while ((cap & (1 << 16)) && msec); if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); // some BIOS versions seem buggy... // return 1; ehci_warn (ehci, "continuing after BIOS bug...\n"); return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } return 0; }
static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) { unsigned char smask = QH_SMASK & hc32_to_cpu(ehci, mask); if (!smask) { ehci_err(ehci, "invalid empty smask!\n"); return 7; } return ffs(smask) - 1; }
static void periodic_tt_usecs ( struct ehci_hcd *ehci, struct usb_device *dev, unsigned frame, unsigned short tt_usecs[8] ) { __hc32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned char uf; memset(tt_usecs, 0, 16); while (q->ptr) { switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { case Q_TYPE_ITD: hw_p = &q->itd->hw_next; q = &q->itd->itd_next; continue; case Q_TYPE_QH: if (same_tt(dev, q->qh->dev)) { uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); tt_usecs[uf] += q->qh->tt_usecs; } hw_p = &q->qh->hw->hw_next; q = &q->qh->qh_next; continue; case Q_TYPE_SITD: if (same_tt(dev, q->sitd->urb->dev)) { uf = tt_start_uframe(ehci, q->sitd->hw_uframe); tt_usecs[uf] += q->sitd->stream->tt_usecs; } hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; continue; default: ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n", frame); hw_p = &q->fstn->hw_next; q = &q->fstn->fstn_next; } } carryover_tt_bandwidth(tt_usecs); if (max_tt_usecs[7] < tt_usecs[7]) ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", frame, tt_usecs[7] - max_tt_usecs[7]); }
static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr, u32 mask, u32 done, int usec) { int error; error = handshake(ehci, ptr, mask, done, usec); if (error) { ehci_halt(ehci); ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n", ptr, mask, done, error); } return error; }
static int ehci_hub_control ( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int ports = HCS_N_PORTS (ehci->hcs_params); u32 temp, status; unsigned long flags; int retval = 0; /* * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. * HCS_INDICATOR may say we can change LEDs to off/amber/green. * (track current state ourselves) ... blink for diagnostics, * power, "this is the one", etc. EHCI spec supports this. */ spin_lock_irqsave (&ehci->lock, flags); switch (typeReq) { case ClearHubFeature: switch (wValue) { case C_HUB_LOCAL_POWER: case C_HUB_OVER_CURRENT: /* no hub-wide feature/status flags */ break; default: goto error; } break; case ClearPortFeature: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = readl (&ehci->regs->port_status [wIndex]); if (temp & PORT_OWNER) break; switch (wValue) { case USB_PORT_FEAT_ENABLE: writel (temp & ~PORT_PE, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_ENABLE: writel((temp & ~PORT_RWC_BITS) | PORT_PEC, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) goto error; if (temp & PORT_SUSPEND) { if ((temp & PORT_PE) == 0) goto error; /* resume signaling for 20 msec */ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); writel (temp | PORT_RESUME, &ehci->regs->port_status [wIndex]); ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (20); } break; case USB_PORT_FEAT_C_SUSPEND: /* we auto-clear this feature */ break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) writel (temp & ~(PORT_RWC_BITS | PORT_POWER), &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_CONNECTION: writel((temp & ~PORT_RWC_BITS) | PORT_CSC, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_OVER_CURRENT: writel((temp & ~PORT_RWC_BITS) | PORT_OCC, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ break; default: goto error; } readl (&ehci->regs->command); /* unblock posted write */ break; case GetHubDescriptor: ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) buf); break; case GetHubStatus: /* no hub-wide feature/status flags */ memset (buf, 0, 4); //cpu_to_le32s ((u32 *) buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; status = 0; temp = readl (&ehci->regs->port_status [wIndex]); // wPortChange bits if (temp & PORT_CSC) status |= 1 << USB_PORT_FEAT_C_CONNECTION; if (temp & PORT_PEC) status |= 1 << USB_PORT_FEAT_C_ENABLE; if (temp & PORT_OCC) status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; /* whoever resumes must GetPortStatus to complete it!! */ if ((temp & PORT_RESUME) && time_after (jiffies, ehci->reset_done [wIndex])) { status |= 1 << USB_PORT_FEAT_C_SUSPEND; ehci->reset_done [wIndex] = 0; /* stop resume signaling */ temp = readl (&ehci->regs->port_status [wIndex]); writel (temp & ~(PORT_RWC_BITS | PORT_RESUME), &ehci->regs->port_status [wIndex]); retval = handshake ( &ehci->regs->port_status [wIndex], PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { ehci_err (ehci, "port %d resume error %d\n", wIndex + 1, retval); goto error; } temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } /* whoever resets must GetPortStatus to complete it!! */ if ((temp & PORT_RESET) && time_after (jiffies, ehci->reset_done [wIndex])) { status |= 1 << USB_PORT_FEAT_C_RESET; ehci->reset_done [wIndex] = 0; /* force reset to complete */ writel (temp & ~(PORT_RWC_BITS | PORT_RESET), &ehci->regs->port_status [wIndex]); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ retval = handshake ( &ehci->regs->port_status [wIndex], PORT_RESET, 0, 750); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", wIndex + 1, retval); goto error; } /* see what we found out */ temp = check_reset_complete (ehci, wIndex, readl (&ehci->regs->port_status [wIndex])); } // don't show wPortStatus if it's owned by a companion hc if (!(temp & PORT_OWNER)) { if (temp & PORT_CONNECT) { status |= 1 << USB_PORT_FEAT_CONNECTION; // status may be from integrated TT status |= ehci_port_speed(ehci, temp); } if (temp & PORT_PE) status |= 1 << USB_PORT_FEAT_ENABLE; if (temp & (PORT_SUSPEND|PORT_RESUME)) status |= 1 << USB_PORT_FEAT_SUSPEND; if (temp & PORT_OC) status |= 1 << USB_PORT_FEAT_OVER_CURRENT; if (temp & PORT_RESET) status |= 1 << USB_PORT_FEAT_RESET; if (temp & PORT_POWER) status |= 1 << USB_PORT_FEAT_POWER; } #ifndef EHCI_VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); // we "know" this alignment is good, caller used kmalloc()... *((__le32 *) buf) = cpu_to_le32 (status); break; case SetHubFeature: switch (wValue) { case C_HUB_LOCAL_POWER: case C_HUB_OVER_CURRENT: /* no hub-wide feature/status flags */ break; default: goto error; } break; case SetPortFeature: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = readl (&ehci->regs->port_status [wIndex]); if (temp & PORT_OWNER) break; temp &= ~PORT_RWC_BITS; switch (wValue) { case USB_PORT_FEAT_SUSPEND: if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) goto error; if (hcd->remote_wakeup) temp |= PORT_WAKE_BITS; writel (temp | PORT_SUSPEND, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) writel (temp | PORT_POWER, &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_RESET: if (temp & PORT_RESUME) goto error; /* line status bits may report this as low speed, * which can be fine if this root hub has a * transaction translator built in. */ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT && !ehci_is_TDI(ehci) && PORT_USB11 (temp)) { ehci_dbg (ehci, "port %d low speed --> companion\n", wIndex + 1); temp |= PORT_OWNER; } else { ehci_vdbg (ehci, "port %d reset\n", wIndex + 1); temp |= PORT_RESET; temp &= ~PORT_PE; /* * caller must wait, then call GetPortStatus * usb 2.0 spec says 50 ms resets on root */ ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); } writel (temp, &ehci->regs->port_status [wIndex]); break; default: goto error; } readl (&ehci->regs->command); /* unblock posted writes */ break; default: error: /* "stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore (&ehci->lock, flags); return retval; }
/* called during probe() after chip reset completes */ static int ehci_pci_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct pci_dev *p_smbus; u8 rev; u32 temp; int retval; int force_otg_hc_mode = 0; switch (pdev->vendor) { case PCI_VENDOR_ID_TOSHIBA_2: /* celleb's companion chip */ if (pdev->device == 0x01b5) { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO ehci->big_endian_mmio = 1; #else ehci_warn(ehci, "unsupported big endian Toshiba quirk\n"); #endif } break; case PCI_VENDOR_ID_INTEL: if (pdev->device == 0x0811 || pdev->device == 0x0829 || pdev->device == 0xE006) { ehci_info(ehci, "Detected Intel MID OTG HC\n"); hcd->has_tt = 1; ehci->has_hostpc = 1; #ifdef CONFIG_USB_OTG ehci->has_otg = 1; #endif force_otg_hc_mode = 1; hcd->has_sram = 1; /* * Disable SRAM for CLVP A0 due to the silicon issue. */ if (pdev->device == 0xE006 && pdev->revision < 0xC) { ehci_info(ehci, "Disable SRAM for CLVP A0\n"); hcd->has_sram = 0; } hcd->sram_no_payload = 1; sram_init(hcd); } else if (pdev->device == 0x0806) { ehci_info(ehci, "Detected Langwell MPH\n"); hcd->has_tt = 1; ehci->has_hostpc = 1; hcd->has_sram = 1; hcd->sram_no_payload = 1; sram_init(hcd); } else if (pdev->device == 0x0829) { ehci_info(ehci, "Detected Penwell OTG HC\n"); hcd->has_tt = 1; ehci->has_hostpc = 1; } else if (pdev->device == 0x08F2) { #ifdef CONFIG_USB_EHCI_HCD_SPH struct ehci_sph_pdata *sph_pdata; sph_pdata = pdev->dev.platform_data; if (!sph_pdata) { ehci_err(ehci, "get SPH platform data failed\n"); retval = -ENODEV; return retval; } /* All need to bypass tll mode */ temp = ehci_readl(ehci, hcd->regs + CLV_SPHCFG); temp &= ~CLV_SPHCFG_ULPI1TYPE; ehci_writel(ehci, temp, hcd->regs + CLV_SPHCFG); sph_pdata->enabled = sph_enabled(); /* Check SPH enabled or not */ if (sph_pdata->enabled == 0) { /* ULPI 1 ref-clock switch off */ temp = ehci_readl(ehci, hcd->regs + CLV_SPHCFG); temp |= CLV_SPHCFG_REFCKDIS; ehci_writel(ehci, temp, hcd->regs + CLV_SPHCFG); /* Set Power state */ retval = pci_set_power_state(pdev, PCI_D1); if (retval < 0) ehci_err(ehci, "Set SPH to D1 failed, retval = %d\n", retval); ehci_info(ehci, "USB SPH is disabled\n"); return -ENODEV; } ehci_info(ehci, "Detected SPH HC\n"); hcd->has_tt = 1; ehci->has_hostpc = 1; temp = ehci_readl(ehci, hcd->regs + CLV_SPH_HOSTPC); temp |= CLV_SPH_HOSTPC_PTS; ehci_writel(ehci, temp, hcd->regs + CLV_SPH_HOSTPC); device_set_wakeup_enable(&pdev->dev, true); /* Set Runtime-PM flags for SPH */ hcd->rpm_control = 1; hcd->rpm_resume = 0; pm_runtime_set_active(&pdev->dev); #endif } else if (pdev->device == 0x119C) { ehci_info(ehci, "Detected Merr USB2 HC\n"); hcd->has_tt = 1; ehci->has_hostpc = 1; } else if (pdev->device == 0x119D) { ehci_info(ehci, "Detected HSIC HC\n"); hcd->has_tt = 1; ehci->has_hostpc = 1; ehci->has_lpm = 0; hcd->has_sram = 1; hcd->sram_no_payload = 1; sram_init(hcd); device_set_wakeup_enable(&pdev->dev, true); /* Set Runtime-PM flags for SPH */ hcd->rpm_control = 1; hcd->rpm_resume = 0; pm_runtime_set_active(&pdev->dev); } } ehci->caps = hcd->regs; ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* ehci_init() causes memory for DMA transfers to be * allocated. Thus, any vendor-specific workarounds based on * limiting the type of memory used for DMA transfers must * happen before ehci_init() is called. */ switch (pdev->vendor) { case PCI_VENDOR_ID_NVIDIA: /* NVidia reports that certain chips don't handle * QH, ITD, or SITD addresses above 2GB. (But TD, * data buffer, and periodic schedule are normal.) */ switch (pdev->device) { case 0x003c: /* MCP04 */ case 0x005b: /* CK804 */ case 0x00d8: /* CK8 */ case 0x00e8: /* CK8S */ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(31)) < 0) ehci_warn(ehci, "can't enable NVidia " "workaround for >2GB RAM\n"); break; } break; } /* cache this readonly data; minimize chip reads */ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); if (force_otg_hc_mode) ehci_reset(ehci); retval = ehci_halt(ehci); if (retval) return retval; if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) || (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) { /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may * read/write memory space which does not belong to it when * there is NULL pointer with T-bit set to 1 in the frame list * table. To avoid the issue, the frame list link pointer * should always contain a valid pointer to a inactive qh. */ ehci->use_dummy_qh = 1; ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI " "dummy qh workaround\n"); } /* data structure init */ retval = ehci_init(hcd); if (retval) return retval; switch (pdev->vendor) { case PCI_VENDOR_ID_NEC: ehci->need_io_watchdog = 0; break; case PCI_VENDOR_ID_INTEL: ehci->need_io_watchdog = 0; ehci->fs_i_thresh = 1; if (pdev->device == 0x27cc) { ehci->broken_periodic = 1; ehci_info(ehci, "using broken periodic workaround\n"); } if (pdev->device == 0x0806 || pdev->device == 0x0811 || pdev->device == 0x0829 || pdev->device == 0xE006) { ehci_info(ehci, "disable lpm for langwell/penwell\n"); ehci->has_lpm = 0; } if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) { hcd->has_tt = 1; tdi_reset(ehci); } break; case PCI_VENDOR_ID_TDI: if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { hcd->has_tt = 1; tdi_reset(ehci); } break; case PCI_VENDOR_ID_AMD: /* AMD PLL quirk */ if (usb_amd_find_chipset_info()) ehci->amd_pll_fix = 1; /* AMD8111 EHCI doesn't work, according to AMD errata */ if (pdev->device == 0x7463) { ehci_info(ehci, "ignoring AMD8111 (errata)\n"); retval = -EIO; goto done; } break; case PCI_VENDOR_ID_NVIDIA: switch (pdev->device) { /* Some NForce2 chips have problems with selective suspend; * fixed in newer silicon. */ case 0x0068: if (pdev->revision < 0xa4) ehci->no_selective_suspend = 1; break; /* MCP89 chips on the MacBookAir3,1 give EPROTO when * fetching device descriptors unless LPM is disabled. * There are also intermittent problems enumerating * devices with PPCD enabled. */ case 0x0d9d: ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89"); ehci->has_lpm = 0; ehci->has_ppcd = 0; ehci->command &= ~CMD_PPCEE; break; } break; case PCI_VENDOR_ID_VIA: if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x60) { u8 tmp; /* The VT6212 defaults to a 1 usec EHCI sleep time which * hogs the PCI bus *badly*. Setting bit 5 of 0x4B makes * that sleep time use the conventional 10 usec. */ pci_read_config_byte(pdev, 0x4b, &tmp); if (tmp & 0x20) break; pci_write_config_byte(pdev, 0x4b, tmp | 0x20); } break; case PCI_VENDOR_ID_ATI: /* AMD PLL quirk */ if (usb_amd_find_chipset_info()) ehci->amd_pll_fix = 1; /* SB600 and old version of SB700 have a bug in EHCI controller, * which causes usb devices lose response in some cases. */ if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) { p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); if (!p_smbus) break; rev = p_smbus->revision; if ((pdev->device == 0x4386) || (rev == 0x3a) || (rev == 0x3b)) { u8 tmp; ehci_info(ehci, "applying AMD SB600/SB700 USB " "freeze workaround\n"); pci_read_config_byte(pdev, 0x53, &tmp); pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); } pci_dev_put(p_smbus); } break; case PCI_VENDOR_ID_NETMOS: /* MosChip frame-index-register bug */ ehci_info(ehci, "applying MosChip frame-index workaround\n"); ehci->frame_index_bug = 1; break; } /* optional debug port, normally in the first BAR */ temp = pci_find_capability(pdev, 0x0a); if (temp) { pci_read_config_dword(pdev, temp, &temp); temp >>= 16; if ((temp & (3 << 13)) == (1 << 13)) { temp &= 0x1fff; ehci->debug = ehci_to_hcd(ehci)->regs + temp; temp = ehci_readl(ehci, &ehci->debug->control); ehci_info(ehci, "debug port %d%s\n", HCS_DEBUG_PORT(ehci->hcs_params), (temp & DBGP_ENABLED) ? " IN USE" : ""); if (!(temp & DBGP_ENABLED)) ehci->debug = NULL; } } ehci_reset(ehci); /* at least the Genesys GL880S needs fixup here */ temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); temp &= 0x0f; if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) { ehci_dbg(ehci, "bogus port configuration: " "cc=%d x pcc=%d < ports=%d\n", HCS_N_CC(ehci->hcs_params), HCS_N_PCC(ehci->hcs_params), HCS_N_PORTS(ehci->hcs_params)); switch (pdev->vendor) { case 0x17a0: /* GENESYS */ /* GL880S: should be PORTS=2 */ temp |= (ehci->hcs_params & ~0xf); ehci->hcs_params = temp; break; case PCI_VENDOR_ID_NVIDIA: /* NF4: should be PCC=10 */ break; } } /* Serial Bus Release Number is at PCI 0x60 offset */ pci_read_config_byte(pdev, 0x60, &ehci->sbrn); if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST) ehci->sbrn = 0x20; /* ConneXT has no sbrn register */ /* Keep this around for a while just in case some EHCI * implementation uses legacy PCI PM support. This test * can be removed on 17 Dec 2009 if the dev_warn() hasn't * been triggered by then. */ if (!device_can_wakeup(&pdev->dev)) { u16 port_wake; pci_read_config_word(pdev, 0x62, &port_wake); if (port_wake & 0x0001) { dev_warn(&pdev->dev, "Enabling legacy PCI PM\n"); device_set_wakeup_capable(&pdev->dev, 1); } } #ifdef CONFIG_USB_SUSPEND /* REVISIT: the controller works fine for wakeup iff the root hub * itself is "globally" suspended, but usbcore currently doesn't * understand such things. * * System suspend currently expects to be able to suspend the entire * device tree, device-at-a-time. If we failed selective suspend * reports, system suspend would fail; so the root hub code must claim * success. That's lying to usbcore, and it matters for runtime * PM scenarios with selective suspend and remote wakeup... */ if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev)) ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); #endif ehci_port_power(ehci, 1); retval = ehci_pci_reinit(ehci, pdev); done: return retval; }
/* how many of the uframe's 125 usecs are allocated? */ static unsigned short periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { __le32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned usecs = 0; while (q->ptr) { switch (Q_NEXT_TYPE (*hw_p)) { case Q_TYPE_QH: /* is it in the S-mask? */ if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe)) usecs += q->qh->usecs; /* ... or C-mask? */ if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe))) usecs += q->qh->c_usecs; hw_p = &q->qh->hw_next; q = &q->qh->qh_next; break; // case Q_TYPE_FSTN: default: /* for "save place" FSTNs, count the relevant INTR * bandwidth from the previous frame */ if (q->fstn->hw_prev != EHCI_LIST_END) { ehci_dbg (ehci, "ignoring FSTN cost ...\n"); } hw_p = &q->fstn->hw_next; q = &q->fstn->fstn_next; break; case Q_TYPE_ITD: usecs += q->itd->usecs [uframe]; hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; case Q_TYPE_SITD: /* is it in the S-mask? (count SPLIT, DATA) */ if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { if (q->sitd->hw_fullspeed_ep & __constant_cpu_to_le32 (1<<31)) usecs += q->sitd->stream->usecs; else /* worst case for OUT start-split */ usecs += HS_USECS_ISO (188); } /* ... C-mask? (count CSPLIT, DATA) */ if (q->sitd->hw_uframe & cpu_to_le32 (1 << (8 + uframe))) { /* worst case for IN complete-split */ usecs += q->sitd->stream->c_usecs; } hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; break; } } #ifdef DEBUG if (usecs > 100) ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", frame * 8 + uframe, usecs); #endif return usecs; }
static int ci_ehci_bus_suspend(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int port; u32 tmp; struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); int ret = orig_bus_suspend(hcd); if (ret) return ret; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status[port]; u32 portsc = ehci_readl(ehci, reg); if (portsc & PORT_CONNECT) { /* * For chipidea, the resume signal will be ended * automatically, so for remote wakeup case, the * usbcmd.rs may not be set before the resume has * ended if other resume paths consumes too much * time (~24ms), in that case, the SOF will not * send out within 3ms after resume ends, then the * high speed device will enter full speed mode. */ tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); /* * It needs a short delay between set RS bit and PHCD. */ usleep_range(150, 200); /* * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended. */ if (ehci_handshake(ehci, reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) ehci_err(ehci, "timeout waiting for SUSPEND\n"); if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) ci_ehci_override_wakeup_flag(ehci, reg, PORT_WKDISC_E | PORT_WKCONN_E, false); if (hcd->usb_phy && test_bit(port, &ehci->bus_suspended) && (ehci_port_speed(ehci, portsc) == USB_PORT_STAT_HIGH_SPEED)) /* * notify the USB PHY, it is for global * suspend case. */ usb_phy_notify_suspend(hcd->usb_phy, USB_SPEED_HIGH); break; } } return 0; }
/* The below code is based on tegra ehci driver */ static int ci_imx_ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 __iomem *status_reg; u32 temp; unsigned long flags; int retval = 0; struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; spin_lock_irqsave(&ehci->lock, flags); if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { retval = -EPIPE; goto done; } temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E); temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); /* * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended. */ if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) ehci_err(ehci, "timeout waiting for SUSPEND\n"); if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) { if (ci->platdata->notify_event) ci->platdata->notify_event (ci, CI_HDRC_IMX_HSIC_SUSPEND_EVENT); ci_ehci_override_wakeup_flag(ehci, status_reg, PORT_WKDISC_E | PORT_WKCONN_E, false); } spin_unlock_irqrestore(&ehci->lock, flags); if (ehci_port_speed(ehci, temp) == USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) { /* notify the USB PHY */ usb_phy_notify_suspend(hcd->usb_phy, USB_SPEED_HIGH); } spin_lock_irqsave(&ehci->lock, flags); set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); goto done; } /* * After resume has finished, it needs do some post resume * operation for some SoCs. */ else if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_C_SUSPEND) { /* Make sure the resume has finished, it should be finished */ if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 25000)) ehci_err(ehci, "timeout waiting for resume\n"); temp = ehci_readl(ehci, status_reg); if (ehci_port_speed(ehci, temp) == USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) { /* notify the USB PHY */ usb_phy_notify_resume(hcd->usb_phy, USB_SPEED_HIGH); } } spin_unlock_irqrestore(&ehci->lock, flags); /* Handle the hub control events here */ return orig_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); done: spin_unlock_irqrestore(&ehci->lock, flags); return retval; }
static unsigned short periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { __hc32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned usecs = 0; struct ehci_qh_hw *hw; while (q->ptr) { switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { case Q_TYPE_QH: hw = q->qh->hw; if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) usecs += q->qh->usecs; if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << (8 + uframe))) usecs += q->qh->c_usecs; hw_p = &hw->hw_next; q = &q->qh->qh_next; break; default: if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) { ehci_dbg (ehci, "ignoring FSTN cost ...\n"); } hw_p = &q->fstn->hw_next; q = &q->fstn->fstn_next; break; case Q_TYPE_ITD: if (q->itd->hw_transaction[uframe]) usecs += q->itd->stream->usecs; hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; case Q_TYPE_SITD: if (q->sitd->hw_uframe & cpu_to_hc32(ehci, 1 << uframe)) { if (q->sitd->hw_fullspeed_ep & cpu_to_hc32(ehci, 1<<31)) usecs += q->sitd->stream->usecs; else usecs += HS_USECS_ISO (188); } if (q->sitd->hw_uframe & cpu_to_hc32(ehci, 1 << (8 + uframe))) { usecs += q->sitd->stream->c_usecs; } hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; break; } } #ifdef DEBUG if (usecs > 100) ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", frame * 8 + uframe, usecs); #endif return usecs; }
static int omap_ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = NULL; u32 temp, temp1, status; unsigned long flags; int retval = 0; u32 runstop, temp_reg; spin_lock_irqsave(&ehci->lock, flags); switch (typeReq) { case GetPortStatus: wIndex--; status = 0; temp = ehci_readl(ehci, status_reg); /* wPortChange bits */ if (temp & PORT_CSC) status |= USB_PORT_STAT_C_CONNECTION << 16; if (temp & PORT_PEC) status |= USB_PORT_STAT_C_ENABLE << 16; if ((temp & PORT_OCC) && !ignore_oc) { status |= USB_PORT_STAT_C_OVERCURRENT << 16; /* * Hubs should disable port power on over-current. * However, not all EHCI implementations do this * automatically, even if they _do_ support per-port * power switching; they're allowed to just limit the * current. khubd will turn the power back on. */ if (HCS_PPC(ehci->hcs_params)) { ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_POWER), status_reg); } } /* whoever resumes must GetPortStatus to complete it!! */ if (temp & PORT_RESUME) { /* Remote Wakeup received? */ if (!ehci->reset_done[wIndex]) { /* resume signaling for 20 msec */ ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); /* check the port again */ mod_timer(&ehci_to_hcd(ehci)->rh_timer, ehci->reset_done[wIndex]); } /* resume completed? */ else if (time_after_eq(jiffies, ehci->reset_done[wIndex])) { clear_bit(wIndex, &ehci->suspended_ports); set_bit(wIndex, &ehci->port_c_suspend); ehci->reset_done[wIndex] = 0; /* * Workaround for OMAP errata: * To Stop Resume Signalling, it is required * to Stop the Host Controller and disable the * TLL Functional Clock. */ /* Stop the Host Controller */ runstop = ehci_readl(ehci, &ehci->regs->command); ehci_writel(ehci, (runstop & ~CMD_RUN), &ehci->regs->command); (void) ehci_readl(ehci, &ehci->regs->command); handshake(ehci, &ehci->regs->status, STS_HALT, STS_HALT, 2000); temp_reg = omap_readl(L3INIT_HSUSBTLL_CLKCTRL); temp_reg &= ~(1 << 9); /* stop resume signaling */ temp = ehci_readl(ehci, status_reg); ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESUME), status_reg); /* Disable the Channel 1 Optional Fclk */ omap_writel(temp_reg, L3INIT_HSUSBTLL_CLKCTRL); retval = handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); /* * Enable the Host Controller and start the * Channel 1 Optional Fclk since resume has * finished. */ udelay(2); omap_writel((temp_reg | (1 << 9)), L3INIT_HSUSBTLL_CLKCTRL); ehci_writel(ehci, (runstop), &ehci->regs->command); (void) ehci_readl(ehci, &ehci->regs->command); if (retval != 0) { ehci_err(ehci, "port %d resume error %d\n", wIndex + 1, retval); spin_unlock_irqrestore(&ehci->lock, flags); return -EPIPE; } temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } } /* whoever resets must GetPortStatus to complete it!! */ if ((temp & PORT_RESET) && time_after_eq(jiffies, ehci->reset_done[wIndex])) { status |= USB_PORT_STAT_C_RESET << 16; ehci->reset_done[wIndex] = 0; /* force reset to complete */ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), status_reg); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ retval = handshake(ehci, status_reg, PORT_RESET, 0, 1000); if (retval != 0) { ehci_err(ehci, "port %d reset error %d\n", wIndex + 1, retval); spin_unlock_irqrestore(&ehci->lock, flags); return -EPIPE; } /* see what we found out */ temp = check_reset_complete(ehci, wIndex, status_reg, ehci_readl(ehci, status_reg)); } if (!(temp & (PORT_RESUME|PORT_RESET))) ehci->reset_done[wIndex] = 0; /* transfer dedicated ports to the companion hc */ if ((temp & PORT_CONNECT) && test_bit(wIndex, &ehci->companion_ports)) { temp &= ~PORT_RWC_BITS; temp |= PORT_OWNER; ehci_writel(ehci, temp, status_reg); ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1); temp = ehci_readl(ehci, status_reg); } /* * Even if OWNER is set, there's no harm letting khubd * see the wPortStatus values (they should all be 0 except * for PORT_POWER anyway). */ if (temp & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; /* status may be from integrated TT */ if (ehci->has_hostpc) { temp1 = ehci_readl(ehci, hostpc_reg); status |= ehci_port_speed(ehci, temp1); } else status |= ehci_port_speed(ehci, temp); } if (temp & PORT_PE) status |= USB_PORT_STAT_ENABLE; /* maybe the port was unsuspended without our knowledge */ if (temp & (PORT_SUSPEND|PORT_RESUME)) { status |= USB_PORT_STAT_SUSPEND; } else if (test_bit(wIndex, &ehci->suspended_ports)) { clear_bit(wIndex, &ehci->suspended_ports); ehci->reset_done[wIndex] = 0; if (temp & PORT_PE) set_bit(wIndex, &ehci->port_c_suspend); } if (temp & PORT_OC) status |= USB_PORT_STAT_OVERCURRENT; if (temp & PORT_RESET) status |= USB_PORT_STAT_RESET; if (temp & PORT_POWER) status |= USB_PORT_STAT_POWER; if (test_bit(wIndex, &ehci->port_c_suspend)) status |= USB_PORT_STAT_C_SUSPEND << 16; #ifndef VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ #endif dbg_port(ehci, "GetStatus", wIndex + 1, temp); put_unaligned_le32(status, buf); break; default: spin_unlock_irqrestore(&ehci->lock, flags); retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); spin_lock_irqsave(&ehci->lock, flags); } spin_unlock_irqrestore(&ehci->lock, flags); return retval; }
static void ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); unsigned long flags; struct ehci_qh *qh, *tmp; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ rescan: spin_lock_irqsave (&ehci->lock, flags); qh = ep->hcpriv; if (!qh) goto done; /* endpoints can be iso streams. for now, we don't * accelerate iso completions ... so spin a while. */ if (qh->hw_info1 == 0) { ehci_vdbg (ehci, "iso delay\n"); goto idle_timeout; } if (!HC_IS_RUNNING (hcd->state)) qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { case QH_STATE_LINKED: for (tmp = ehci->async->qh_next.qh; tmp && tmp != qh; tmp = tmp->qh_next.qh) continue; /* periodic qh self-unlinks on empty */ if (!tmp) goto nogood; unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); goto rescan; case QH_STATE_IDLE: /* fully unlinked */ if (list_empty (&qh->qtd_list)) { qh_put (qh); break; } /* else FALL THROUGH */ default: nogood: /* caller was supposed to have unlinked any requests; * that's not our job. just leak this memory. */ ehci_err (ehci, "qh %p (#%02x) state %d%s\n", qh, ep->desc.bEndpointAddress, qh->qh_state, list_empty (&qh->qtd_list) ? "" : "(has tds)"); break; } ep->hcpriv = NULL; done: spin_unlock_irqrestore (&ehci->lock, flags); return; }
static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; int rc; spin_lock_irqsave (&ehci->lock, flags); rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (rc) goto done; switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: default: qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; switch (qh->qh_state) { case QH_STATE_LINKED: case QH_STATE_COMPLETING: unlink_async(ehci, qh); break; case QH_STATE_UNLINK: case QH_STATE_UNLINK_WAIT: /* already started */ break; case QH_STATE_IDLE: WARN_ON(1); break; } break; case PIPE_INTERRUPT: qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; switch (qh->qh_state) { case QH_STATE_LINKED: intr_deschedule (ehci, qh); /* FALL THROUGH */ case QH_STATE_IDLE: qh_completions (ehci, qh); break; default: ehci_dbg (ehci, "bogus qh %p state %d\n", qh, qh->qh_state); goto done; } /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) && HC_IS_RUNNING (hcd->state)) { rc = qh_schedule(ehci, qh); /* An error here likely indicates handshake failure * or no space left in the schedule. Neither fault * should happen often ... * * FIXME kill the now-dysfunctional queued urbs */ if (rc != 0) ehci_err(ehci, "can't reschedule qh %p, err %d", qh, rc); } break; case PIPE_ISOCHRONOUS: // itd or sitd ... // wait till next completion, do it then. // completion irqs can wait up to 1024 msec, break; } done: spin_unlock_irqrestore (&ehci->lock, flags); return rc; }
static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status, masked_status, pcd_status = 0, cmd; int bh; spin_lock (&ehci->lock); status = ehci_readl(ehci, &ehci->regs->status); /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { ehci_dbg (ehci, "device removed\n"); goto dead; } masked_status = status & INTR_MASK; if (!masked_status) { /* irq sharing? */ spin_unlock(&ehci->lock); return IRQ_NONE; } /* clear (just) interrupts */ ehci_writel(ehci, masked_status, &ehci->regs->status); cmd = ehci_readl(ehci, &ehci->regs->command); bh = 0; #ifdef VERBOSE_DEBUG /* unrequested/ignored: Frame List Rollover */ dbg_status (ehci, "irq", status); #endif /* INT, ERR, and IAA interrupt rates can be throttled */ /* normal [4.15.1.2] or error [4.15.1.1] completion */ if (likely ((status & (STS_INT|STS_ERR)) != 0)) { if (likely ((status & STS_ERR) == 0)) COUNT (ehci->stats.normal); else COUNT (ehci->stats.error); bh = 1; } /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { /* guard against (alleged) silicon errata */ if (cmd & CMD_IAAD) { ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command); ehci_dbg(ehci, "IAA with IAAD still set?\n"); } if (ehci->reclaim) { COUNT(ehci->stats.reclaim); end_unlink_async(ehci); } else ehci_dbg(ehci, "IAA with nothing to reclaim?\n"); } /* remote wakeup [4.3.1] */ if (status & STS_PCD) { unsigned i = HCS_N_PORTS (ehci->hcs_params); /* kick root hub later */ pcd_status = status; /* resume root hub? */ if (!(cmd & CMD_RUN)) usb_hcd_resume_root_hub(hcd); while (i--) { int pstatus = ehci_readl(ehci, &ehci->regs->port_status [i]); if (pstatus & PORT_OWNER) continue; if (!(test_bit(i, &ehci->suspended_ports) && ((pstatus & PORT_RESUME) || !(pstatus & PORT_SUSPEND)) && (pstatus & PORT_PE) && ehci->reset_done[i] == 0)) continue; /* start 20 msec resume signaling from this port, * and make khubd collect PORT_STAT_C_SUSPEND to * stop that signaling. */ ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); mod_timer(&hcd->rh_timer, ehci->reset_done[i]); } } /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { ehci_err(ehci, "fatal error\n"); dbg_cmd(ehci, "fatal", cmd); dbg_status(ehci, "fatal", status); ehci_halt(ehci); dead: ehci_reset(ehci); ehci_writel(ehci, 0, &ehci->regs->configured_flag); /* generic layer kills/unlinks all urbs, then * uses ehci_stop to clean up the rest */ bh = 1; } if (bh) ehci_work (ehci); spin_unlock (&ehci->lock); if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; }