11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2d49d431744007cec0ee1a3ade96f9e0f100c7907David Brownell * Copyright (C) 2001-2004 by David Brownell 353bd6a601a87bb6d0df844872bc15fd4e8d127ceDavid Brownell * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * option) any later version. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for more details. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software Foundation, 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* this file is part of ehci-hcd.c */ 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EHCI Root Hub ... the nonsharable stuff 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Registers don't need cpu_to_le32, that happens transparently 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 3083722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin#include <linux/usb/otg.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3258a97ffeb2297f154659f339d77eb3f32c4d8b3eAlan Stern#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) 3358a97ffeb2297f154659f339d77eb3f32c4d8b3eAlan Stern 34aff6d18f95bb81b2d07994372c8edcc2c2b41180Alan Stern#ifdef CONFIG_PM 35aff6d18f95bb81b2d07994372c8edcc2c2b41180Alan Stern 36383975d765523a56dc43a6cd6d52e9b376800cf2Alan Sternstatic int ehci_hub_control( 37383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern struct usb_hcd *hcd, 38383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u16 typeReq, 39383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u16 wValue, 40383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u16 wIndex, 41383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern char *buf, 42383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u16 wLength 43383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern); 44383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 45383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern/* After a power loss, ports that were owned by the companion must be 46383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern * reset so that the companion can still own them. 47383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern */ 48383975d765523a56dc43a6cd6d52e9b376800cf2Alan Sternstatic void ehci_handover_companion_ports(struct ehci_hcd *ehci) 49383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern{ 50383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u32 __iomem *reg; 51383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u32 status; 52383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern int port; 53383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern __le32 buf; 54383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern struct usb_hcd *hcd = ehci_to_hcd(ehci); 55383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 56383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (!ehci->owned_ports) 57383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern return; 58383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 59383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern /* Give the connections some time to appear */ 60383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern msleep(20); 61383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 62383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern port = HCS_N_PORTS(ehci->hcs_params); 63383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern while (port--) { 64383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (test_bit(port, &ehci->owned_ports)) { 65383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern reg = &ehci->regs->port_status[port]; 663c519b846c4d5edf7c94d1eede42445a815bf65cAlan Stern status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 67383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 68383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern /* Port already owned by companion? */ 69383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (status & PORT_OWNER) 70383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern clear_bit(port, &ehci->owned_ports); 713c519b846c4d5edf7c94d1eede42445a815bf65cAlan Stern else if (test_bit(port, &ehci->companion_ports)) 723c519b846c4d5edf7c94d1eede42445a815bf65cAlan Stern ehci_writel(ehci, status & ~PORT_PE, reg); 73383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern else 74383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci_hub_control(hcd, SetPortFeature, 75383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern USB_PORT_FEAT_RESET, port + 1, 76383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern NULL, 0); 77383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern } 78383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern } 79383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 80383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (!ehci->owned_ports) 81383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern return; 82383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern msleep(90); /* Wait for resets to complete */ 83383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 84383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern port = HCS_N_PORTS(ehci->hcs_params); 85383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern while (port--) { 86383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (test_bit(port, &ehci->owned_ports)) { 87383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci_hub_control(hcd, GetPortStatus, 88383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 0, port + 1, 89383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern (char *) &buf, sizeof(buf)); 90383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 91383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern /* The companion should now own the port, 92383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern * but if something went wrong the port must not 93383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern * remain enabled. 94383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern */ 95383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern reg = &ehci->regs->port_status[port]; 96383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 97383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (status & PORT_OWNER) 98383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci_writel(ehci, status | PORT_CSC, reg); 99383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern else { 100383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci_dbg(ehci, "failed handover port %d: %x\n", 101383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern port + 1, status); 102383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci_writel(ehci, status & ~PORT_PE, reg); 103383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern } 104383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern } 105383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern } 106383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 107383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci->owned_ports = 0; 108383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern} 109383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern 1105407a3c3d942e75d4d123d213fd692bce5acc961Felipe Balbistatic int __maybe_unused ehci_port_change(struct ehci_hcd *ehci) 111294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett{ 112294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett int i = HCS_N_PORTS(ehci->hcs_params); 113294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett 114294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett /* First check if the controller indicates a change event */ 115294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett 116294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD) 117294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett return 1; 118294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett 119294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett /* 120294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett * Not all controllers appear to update this while going from D3 to D0, 121294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett * so check the individual port status registers as well 122294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett */ 123294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett 124294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett while (i--) 125294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC) 126294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett return 1; 127294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett 128294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett return 0; 129294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett} 130294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett 1310b0cd6c81defc4e4fccb9e9103666547fefdb9c0Fabio Estevamstatic __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, 1324147200d25c423e627ab4487530b3d9f2ef829c8Alan Stern bool suspending, bool do_wakeup) 13316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern{ 13416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern int port; 13516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 temp; 136148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai unsigned long flags; 13716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 13816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* If remote wakeup is enabled for the root hub but disabled 13916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern * for the controller, we must adjust all the port wakeup flags 14016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern * when the controller is suspended or resumed. In all other 14116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern * cases they don't need to be changed. 14216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern */ 1434147200d25c423e627ab4487530b3d9f2ef829c8Alan Stern if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) 14416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern return; 14516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 146148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai spin_lock_irqsave(&ehci->lock, flags); 147148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai 14816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* clear phy low-power mode before changing wakeup flags */ 14916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (ehci->has_hostpc) { 15016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern port = HCS_N_PORTS(ehci->hcs_params); 15116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern while (port--) { 15216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 __iomem *hostpc_reg; 15316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 15416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs 15516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern + HOSTPC0 + 4 * port); 15616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern temp = ehci_readl(ehci, hostpc_reg); 15716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); 15816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 159148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai spin_unlock_irqrestore(&ehci->lock, flags); 16016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern msleep(5); 161148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai spin_lock_irqsave(&ehci->lock, flags); 16216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 16316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 16416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern port = HCS_N_PORTS(ehci->hcs_params); 16516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern while (port--) { 16616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 __iomem *reg = &ehci->regs->port_status[port]; 16716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 16816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 t2 = t1 & ~PORT_WAKE_BITS; 16916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 17016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* If we are suspending the controller, clear the flags. 17116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern * If we are resuming the controller, set the wakeup flags. 17216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern */ 17316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (!suspending) { 17416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (t1 & PORT_CONNECT) 17516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern t2 |= PORT_WKOC_E | PORT_WKDISC_E; 17616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern else 17716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern t2 |= PORT_WKOC_E | PORT_WKCONN_E; 17816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 17916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_vdbg(ehci, "port %d, %08x -> %08x\n", 18016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern port + 1, t1, t2); 18116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, t2, reg); 18216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 18316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 18416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* enter phy low-power mode again */ 18516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (ehci->has_hostpc) { 18616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern port = HCS_N_PORTS(ehci->hcs_params); 18716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern while (port--) { 18816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 __iomem *hostpc_reg; 18916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 19016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs 19116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern + HOSTPC0 + 4 * port); 19216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern temp = ehci_readl(ehci, hostpc_reg); 19316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg); 19416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 19516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 196ee0b9be829803e3ff5adec7456bd59a08425ffa1Alan Stern 197ee0b9be829803e3ff5adec7456bd59a08425ffa1Alan Stern /* Does the root hub have a port wakeup pending? */ 198294d95f2cbc2aef5346258f216cd9df570e271a5Matthew Garrett if (!suspending && ehci_port_change(ehci)) 199ee0b9be829803e3ff5adec7456bd59a08425ffa1Alan Stern usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); 200148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai 201148fc55fd0449683a1d15bf219ad8d8b6fa17545Yin Kangkai spin_unlock_irqrestore(&ehci->lock, flags); 20216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern} 20316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 2040c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int ehci_bus_suspend (struct usb_hcd *hcd) 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ehci_hcd *ehci = hcd_to_ehci (hcd); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int port; 2088c03356a559ced6fa78931f498193f776d67e445Alan Stern int mask; 20916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern int changed; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2118c774fe8a0284aff9e4c7ea43f5154fd46da325cAlan Stern ehci_dbg(ehci, "suspend root hub\n"); 2128c774fe8a0284aff9e4c7ea43f5154fd46da325cAlan Stern 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_before (jiffies, ehci->next_statechange)) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(5); 215f8fa7571a928d6d0e1b7444b0ea69ec7dc7db3b6Alan Stern del_timer_sync(&ehci->watchdog); 216f8fa7571a928d6d0e1b7444b0ea69ec7dc7db3b6Alan Stern del_timer_sync(&ehci->iaa_watchdog); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq (&ehci->lock); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 220cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern /* Once the controller is stopped, port resumes that are already 221cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern * in progress won't complete. Hence if remote wakeup is enabled 222cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern * for the root hub and any ports are in the middle of a resume or 223cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern * remote wakeup, we must fail the suspend. 224cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern */ 225cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern if (hcd->self.root_hub->do_remote_wakeup) { 226a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern if (ehci->resuming_ports) { 227a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern spin_unlock_irq(&ehci->lock); 228a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern ehci_dbg(ehci, "suspend failed because a port is resuming\n"); 229a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern return -EBUSY; 230cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern } 231cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern } 232cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* stop schedules, clean any completed work */ 234e8799906045302776b35b66b16495c575db3b69cAlan Stern if (ehci->rh_state == EHCI_RH_RUNNING) 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_quiesce (ehci); 236083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci->command = ehci_readl(ehci, &ehci->regs->command); 2377d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells ehci_work(ehci); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2398c03356a559ced6fa78931f498193f776d67e445Alan Stern /* Unlike other USB host controller types, EHCI doesn't have 2408c03356a559ced6fa78931f498193f776d67e445Alan Stern * any notion of "global" or bus-wide suspend. The driver has 2418c03356a559ced6fa78931f498193f776d67e445Alan Stern * to manually suspend all the active unsuspended ports, and 2428c03356a559ced6fa78931f498193f776d67e445Alan Stern * then manually resume them in the bus_resume() routine. 2438c03356a559ced6fa78931f498193f776d67e445Alan Stern */ 2448c03356a559ced6fa78931f498193f776d67e445Alan Stern ehci->bus_suspended = 0; 245383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci->owned_ports = 0; 24616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern changed = 0; 247cec3a53c7fe794237b582e8e77fc0e48465e65eeAlan Stern port = HCS_N_PORTS(ehci->hcs_params); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (port--) { 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 __iomem *reg = &ehci->regs->port_status [port]; 250083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 25116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 t2 = t1 & ~PORT_WAKE_BITS; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2538c03356a559ced6fa78931f498193f776d67e445Alan Stern /* keep track of which ports we suspend */ 254383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern if (t1 & PORT_OWNER) 255383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern set_bit(port, &ehci->owned_ports); 256383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) { 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t2 |= PORT_SUSPEND; 2588c03356a559ced6fa78931f498193f776d67e445Alan Stern set_bit(port, &ehci->bus_suspended); 2598c03356a559ced6fa78931f498193f776d67e445Alan Stern } 2608c03356a559ced6fa78931f498193f776d67e445Alan Stern 26116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* enable remote wakeup on all ports, if told to do so */ 262331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du if (hcd->self.root_hub->do_remote_wakeup) { 263331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du /* only enable appropriate wake bits, otherwise the 264331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du * hardware can not go phy low power mode. If a race 265331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du * condition happens here(connection change during bits 266331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du * set), the port change detection will finally fix it. 267331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du */ 26816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (t1 & PORT_CONNECT) 269331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du t2 |= PORT_WKOC_E | PORT_WKDISC_E; 27016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern else 271331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du t2 |= PORT_WKOC_E | PORT_WKCONN_E; 27216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (t1 != t2) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_vdbg (ehci, "port %d, %08x -> %08x\n", 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port + 1, t1, t2); 277083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, t2, reg); 27816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern changed = 1; 27916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 28016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 281331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du 28216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (changed && ehci->has_hostpc) { 28316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern spin_unlock_irq(&ehci->lock); 28416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern msleep(5); /* 5 ms for HCD to enter low-power mode */ 28516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern spin_lock_irq(&ehci->lock); 28616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 28716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern port = HCS_N_PORTS(ehci->hcs_params); 28816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern while (port--) { 28916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 __iomem *hostpc_reg; 29016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 t3; 29116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 29216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs 29316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern + HOSTPC0 + 4 * port); 29416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern t3 = ehci_readl(ehci, hostpc_reg); 29516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); 29616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern t3 = ehci_readl(ehci, hostpc_reg); 29716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_dbg(ehci, "Port %d phy low-power mode %s\n", 298331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du port, (t3 & HOSTPC_PHCD) ? 299331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du "succeeded" : "failed"); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 303cd930c931417295ac6b4d9fea62accc67192ac34Alan Stern /* Apparently some devices need a >= 1-uframe delay here */ 304cd930c931417295ac6b4d9fea62accc67192ac34Alan Stern if (ehci->bus_suspended) 305cd930c931417295ac6b4d9fea62accc67192ac34Alan Stern udelay(150); 306cd930c931417295ac6b4d9fea62accc67192ac34Alan Stern 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* turn off now-idle HC */ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_halt (ehci); 309e8799906045302776b35b66b16495c575db3b69cAlan Stern ehci->rh_state = EHCI_RH_SUSPENDED; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311cdc647a9b75741659bfc6acc44a6b3a646ad53bfDavid Brownell if (ehci->reclaim) 312cdc647a9b75741659bfc6acc44a6b3a646ad53bfDavid Brownell end_unlink_async(ehci); 313cdc647a9b75741659bfc6acc44a6b3a646ad53bfDavid Brownell 3148c03356a559ced6fa78931f498193f776d67e445Alan Stern /* allow remote wakeup */ 3158c03356a559ced6fa78931f498193f776d67e445Alan Stern mask = INTR_MASK; 31658a97ffeb2297f154659f339d77eb3f32c4d8b3eAlan Stern if (!hcd->self.root_hub->do_remote_wakeup) 3178c03356a559ced6fa78931f498193f776d67e445Alan Stern mask &= ~STS_PCD; 318083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, mask, &ehci->regs->intr_enable); 319083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_readl(ehci, &ehci->regs->intr_enable); 3208c03356a559ced6fa78931f498193f776d67e445Alan Stern 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci->next_statechange = jiffies + msecs_to_jiffies(10); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq (&ehci->lock); 323015798b2f166725b1dae2b07b5ffb127ab187be0Jon Hunter 324015798b2f166725b1dae2b07b5ffb127ab187be0Jon Hunter /* ehci_work() may have re-enabled the watchdog timer, which we do not 325015798b2f166725b1dae2b07b5ffb127ab187be0Jon Hunter * want, and so we must delete any pending watchdog timer events. 326015798b2f166725b1dae2b07b5ffb127ab187be0Jon Hunter */ 327015798b2f166725b1dae2b07b5ffb127ab187be0Jon Hunter del_timer_sync(&ehci->watchdog); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller has locked the root hub, and should reset/reinit on error */ 3330c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int ehci_bus_resume (struct usb_hcd *hcd) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ehci_hcd *ehci = hcd_to_ehci (hcd); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 temp; 337383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u32 power_okay; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 339d0f2fb2500b1c5fe4967eb45d8c9bc758d7aef80Wang Zhi unsigned long resume_needed = 0; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_before (jiffies, ehci->next_statechange)) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(5); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq (&ehci->lock); 344541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern if (!HCD_HW_ACCESSIBLE(hcd)) { 345cfa59dab27d1b282886e7772a8f9548236883892Alan Stern spin_unlock_irq(&ehci->lock); 346cfa59dab27d1b282886e7772a8f9548236883892Alan Stern return -ESHUTDOWN; 347cfa59dab27d1b282886e7772a8f9548236883892Alan Stern } 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 349ad45f1dc836cb175e9aeea927837dd48039d652cJason Wessel if (unlikely(ehci->debug)) { 350872d3599622702b59a00521c0a5b8ff3822e1803Jason Wessel if (!dbgp_reset_prep()) 351ad45f1dc836cb175e9aeea927837dd48039d652cJason Wessel ehci->debug = NULL; 352ad45f1dc836cb175e9aeea927837dd48039d652cJason Wessel else 353ad45f1dc836cb175e9aeea927837dd48039d652cJason Wessel dbgp_external_startup(); 354ad45f1dc836cb175e9aeea927837dd48039d652cJason Wessel } 355ad45f1dc836cb175e9aeea927837dd48039d652cJason Wessel 356f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell /* Ideally and we've got a real resume here, and no port's power 357f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell * was lost. (For PCI, that means Vaux was maintained.) But we 358f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell * could instead be restoring a swsusp snapshot -- so that BIOS was 359f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell * the last user of the controller, not reset/pm hardware keeping 360f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell * state we gave to it. 361f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell */ 362383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern power_okay = ehci_readl(ehci, &ehci->regs->intr_enable); 363383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern ehci_dbg(ehci, "resume root hub%s\n", 364383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern power_okay ? "" : " after power loss"); 365f03c17fc9abe8582d6ad830290b3093fdf1eea61David Brownell 3668c03356a559ced6fa78931f498193f776d67e445Alan Stern /* at least some APM implementations will try to deliver 3678c03356a559ced6fa78931f498193f776d67e445Alan Stern * IRQs right away, so delay them until we're ready. 3688c03356a559ced6fa78931f498193f776d67e445Alan Stern */ 369083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, 0, &ehci->regs->intr_enable); 3708c03356a559ced6fa78931f498193f776d67e445Alan Stern 3718c03356a559ced6fa78931f498193f776d67e445Alan Stern /* re-init operational registers */ 372083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, 0, &ehci->regs->segment); 373083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); 374083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* restore CMD_RUN, framelist size, and irq threshold */ 377083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, ehci->command, &ehci->regs->command); 378e8799906045302776b35b66b16495c575db3b69cAlan Stern ehci->rh_state = EHCI_RH_RUNNING; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 380e198a31489146bb723fef179e5d1d18c8225f246Alan Stern /* Some controller/firmware combinations need a delay during which 381e198a31489146bb723fef179e5d1d18c8225f246Alan Stern * they set up the port statuses. See Bugzilla #8190. */ 3823a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita spin_unlock_irq(&ehci->lock); 3833a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita msleep(8); 3843a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita spin_lock_irq(&ehci->lock); 385e198a31489146bb723fef179e5d1d18c8225f246Alan Stern 38616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* clear phy low-power mode before resume */ 38716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (ehci->bus_suspended && ehci->has_hostpc) { 38816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern i = HCS_N_PORTS(ehci->hcs_params); 38916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern while (i--) { 39016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (test_bit(i, &ehci->bus_suspended)) { 39116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern u32 __iomem *hostpc_reg; 39216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 39316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs 39416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern + HOSTPC0 + 4 * i); 39516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern temp = ehci_readl(ehci, hostpc_reg); 39616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, temp & ~HOSTPC_PHCD, 39716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern hostpc_reg); 39816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 39916032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 40016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern spin_unlock_irq(&ehci->lock); 40116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern msleep(5); 40216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern spin_lock_irq(&ehci->lock); 40316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern } 40416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 4058c03356a559ced6fa78931f498193f776d67e445Alan Stern /* manually resume the ports we suspended during bus_suspend() */ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = HCS_N_PORTS (ehci->hcs_params); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i--) { 408083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt temp = ehci_readl(ehci, &ehci->regs->port_status [i]); 40958a97ffeb2297f154659f339d77eb3f32c4d8b3eAlan Stern temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); 4108c03356a559ced6fa78931f498193f776d67e445Alan Stern if (test_bit(i, &ehci->bus_suspended) && 4113a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita (temp & PORT_SUSPEND)) { 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= PORT_RESUME; 413d0f2fb2500b1c5fe4967eb45d8c9bc758d7aef80Wang Zhi set_bit(i, &resume_needed); 4143a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita } 415083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, temp, &ehci->regs->port_status [i]); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4173a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita 4183a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita /* msleep for 20ms only if code is trying to resume port */ 4193a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita if (resume_needed) { 4203a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita spin_unlock_irq(&ehci->lock); 4213a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita msleep(20); 4223a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita spin_lock_irq(&ehci->lock); 4233a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita } 4243a4e72cbf2ac4435630a2b03bd25e60ef5967e99Vikram Pandita 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = HCS_N_PORTS (ehci->hcs_params); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i--) { 427083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt temp = ehci_readl(ehci, &ehci->regs->port_status [i]); 428d0f2fb2500b1c5fe4967eb45d8c9bc758d7aef80Wang Zhi if (test_bit(i, &resume_needed)) { 4298c03356a559ced6fa78931f498193f776d67e445Alan Stern temp &= ~(PORT_RWC_BITS | PORT_RESUME); 430083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, temp, &ehci->regs->port_status [i]); 4318c03356a559ced6fa78931f498193f776d67e445Alan Stern ehci_vdbg (ehci, "resumed port %d\n", i + 1); 4328c03356a559ced6fa78931f498193f776d67e445Alan Stern } 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 434083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt (void) ehci_readl(ehci, &ehci->regs->command); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* maybe re-activate the schedule(s) */ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = 0; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ehci->async->qh_next.qh) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= CMD_ASE; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ehci->periodic_sched) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= CMD_PSE; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp) { 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci->command |= temp; 444083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, ehci->command, &ehci->regs->command); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci->next_statechange = jiffies + msecs_to_jiffies(5); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now we can safely re-enable irqs */ 450083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq (&ehci->lock); 4533bb1af5243d41af9518728445e9c9bd30dd47237Alan Stern ehci_handover_companion_ports(ehci); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4590c0382e32d46f606951010b202382be14d180a17Alan Stern#define ehci_bus_suspend NULL 4600c0382e32d46f606951010b202382be14d180a17Alan Stern#define ehci_bus_resume NULL 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PM */ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46657e06c11372eccf5acebdd4664eb025fee76c561Alan Stern/* 46790da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao * Sets the owner of a port 46857e06c11372eccf5acebdd4664eb025fee76c561Alan Stern */ 46990da096ee46b682011b7d549e52b81cf9742e60bBalaji Raostatic void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) 47057e06c11372eccf5acebdd4664eb025fee76c561Alan Stern{ 47157e06c11372eccf5acebdd4664eb025fee76c561Alan Stern u32 __iomem *status_reg; 47257e06c11372eccf5acebdd4664eb025fee76c561Alan Stern u32 port_status; 47390da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao int try; 47457e06c11372eccf5acebdd4664eb025fee76c561Alan Stern 47590da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao status_reg = &ehci->regs->port_status[portnum]; 47657e06c11372eccf5acebdd4664eb025fee76c561Alan Stern 47757e06c11372eccf5acebdd4664eb025fee76c561Alan Stern /* 47857e06c11372eccf5acebdd4664eb025fee76c561Alan Stern * The controller won't set the OWNER bit if the port is 47957e06c11372eccf5acebdd4664eb025fee76c561Alan Stern * enabled, so this loop will sometimes require at least two 48057e06c11372eccf5acebdd4664eb025fee76c561Alan Stern * iterations: one to disable the port and one to set OWNER. 48157e06c11372eccf5acebdd4664eb025fee76c561Alan Stern */ 48257e06c11372eccf5acebdd4664eb025fee76c561Alan Stern for (try = 4; try > 0; --try) { 48357e06c11372eccf5acebdd4664eb025fee76c561Alan Stern spin_lock_irq(&ehci->lock); 48457e06c11372eccf5acebdd4664eb025fee76c561Alan Stern port_status = ehci_readl(ehci, status_reg); 48557e06c11372eccf5acebdd4664eb025fee76c561Alan Stern if ((port_status & PORT_OWNER) == new_owner 48657e06c11372eccf5acebdd4664eb025fee76c561Alan Stern || (port_status & (PORT_OWNER | PORT_CONNECT)) 48757e06c11372eccf5acebdd4664eb025fee76c561Alan Stern == 0) 48857e06c11372eccf5acebdd4664eb025fee76c561Alan Stern try = 0; 48957e06c11372eccf5acebdd4664eb025fee76c561Alan Stern else { 49057e06c11372eccf5acebdd4664eb025fee76c561Alan Stern port_status ^= PORT_OWNER; 49157e06c11372eccf5acebdd4664eb025fee76c561Alan Stern port_status &= ~(PORT_PE | PORT_RWC_BITS); 49257e06c11372eccf5acebdd4664eb025fee76c561Alan Stern ehci_writel(ehci, port_status, status_reg); 49357e06c11372eccf5acebdd4664eb025fee76c561Alan Stern } 49457e06c11372eccf5acebdd4664eb025fee76c561Alan Stern spin_unlock_irq(&ehci->lock); 49557e06c11372eccf5acebdd4664eb025fee76c561Alan Stern if (try > 1) 49657e06c11372eccf5acebdd4664eb025fee76c561Alan Stern msleep(5); 49757e06c11372eccf5acebdd4664eb025fee76c561Alan Stern } 49890da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao} 49990da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao 50057e06c11372eccf5acebdd4664eb025fee76c561Alan Stern/*-------------------------------------------------------------------------*/ 50157e06c11372eccf5acebdd4664eb025fee76c561Alan Stern 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_reset_complete ( 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ehci_hcd *ehci, 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int index, 505e6316565e568b3b5733be10cfca3c27259bef499Alan Stern u32 __iomem *status_reg, 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int port_status 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 508cd4cdc93ce04b562412df6c0cf25c564ab2522acDavid Brownell if (!(port_status & PORT_CONNECT)) 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return port_status; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if reset finished and it's still not enabled -- handoff */ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(port_status & PORT_PE)) { 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* with integrated TT, there's nobody to hand it to! */ 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ehci_is_TDI(ehci)) { 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_dbg (ehci, 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Failed to enable port %d on root hub TT\n", 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index+1); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return port_status; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_dbg (ehci, "port %d full speed --> companion\n", 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index + 1); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // what happens if HCS_N_CC(params) == 0 ? 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port_status |= PORT_OWNER; 52710f6524a8ef1413a8cbd952673997013183fe2a9David Brownell port_status &= ~PORT_RWC_BITS; 528e6316565e568b3b5733be10cfca3c27259bef499Alan Stern ehci_writel(ehci, port_status, status_reg); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 530796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug /* ensure 440EPX ohci controller state is operational */ 531796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug if (ehci->has_amcc_usb23) 532796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug set_ohci_hcfs(ehci, 1); 533796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug } else { 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_dbg (ehci, "port %d high speed\n", index + 1); 535796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug /* ensure 440EPx ohci controller state is suspended */ 536796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug if (ehci->has_amcc_usb23) 537796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug set_ohci_hcfs(ehci, 0); 538796bcae7361c28cf825780f6f1aac9dd3411394eVitaly Bordug } 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return port_status; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* build "status change" packet (one or two bytes) from HC registers */ 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsehci_hub_status_data (struct usb_hcd *hcd, char *buf) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ehci_hcd *ehci = hcd_to_ehci (hcd); 552a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern u32 temp, status; 55393f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell u32 mask; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ports, i, retval = 1; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5565a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du u32 ppcd = 0; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* init status to no-changes */ 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] = 0; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports = HCS_N_PORTS (ehci->hcs_params); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ports > 7) { 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [1] = 0; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval++; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 56553bd6a601a87bb6d0df844872bc15fd4e8d127ceDavid Brownell 566a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern /* Inform the core about resumes-in-progress by returning 567a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern * a non-zero value even if there are no status changes. 568a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern */ 569a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern status = ehci->resuming_ports; 570a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern 57193f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell /* Some boards (mostly VIA?) report bogus overcurrent indications, 57293f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell * causing massive log spam unless we completely ignore them. It 5733a4fa0a25da81600ea0bcd75692ae8ca6050d165Robert P. J. Day * may be relevant that VIA VT8235 controllers, where PORT_POWER is 57493f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell * always set, seem to clear PORT_OCC and PORT_CSC when writing to 57593f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell * PORT_POWER; that's surprising, but maybe within-spec. 57693f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell */ 57793f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell if (!ignore_oc) 57893f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell mask = PORT_CSC | PORT_PEC | PORT_OCC; 57993f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell else 58093f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell mask = PORT_CSC | PORT_PEC; 58193f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell // PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND 58293f1a47c4af34c4ee014b3d2aae70089b3b69f72David Brownell 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no hub change reports (bit 0) for now (power, ...) */ 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* port N changes (bit N)? */ 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&ehci->lock, flags); 5875a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du 5885a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du /* get per-port change detect bits */ 5895a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du if (ehci->has_ppcd) 5905a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16; 5915a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ports; i++) { 5935a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du /* leverage per-port change bits feature */ 5945a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du if (ehci->has_ppcd && !(ppcd & (1 << i))) 5955a9cdf332eae724b11906cb1712e3a662eba32b2Alek Du continue; 596083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt temp = ehci_readl(ehci, &ehci->regs->port_status [i]); 597625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern 598625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern /* 599625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * Return status information even for ports with OWNER set. 600625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * Otherwise khubd wouldn't see the disconnect event when a 601625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * high-speed device is switched over to the companion 602625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * controller by the user. 603625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern */ 604625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern 605eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend) 606eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern || (ehci->reset_done[i] && time_after_eq( 607eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern jiffies, ehci->reset_done[i]))) { 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i < 7) 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [0] |= 1 << (i + 1); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf [1] |= 1 << (i - 7); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = STS_PCD; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME autosuspend idle root hubs */ 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&ehci->lock, flags); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status ? retval : 0; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsehci_hub_descriptor ( 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ehci_hcd *ehci, 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hub_descriptor *desc 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ports = HCS_N_PORTS (ehci->hcs_params); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 temp; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescriptorType = 0x29; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bPwrOn2PwrGood = 10; /* ehci 1.0, 2.3.9 says 20ms max */ 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bHubContrCurrent = 0; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bNbrPorts = ports; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = 1 + (ports / 8); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds desc->bDescLength = 7 + 2 * temp; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ 639dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn memset(&desc->u.hs.DeviceRemovable[0], 0, temp); 640dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = 0x0008; /* per-port overcurrent reporting */ 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HCS_PPC (ehci->hcs_params)) 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= 0x0001; /* per-port power control */ 64556c1e26d75008d39f1067f453719857a81109d9fDavid Brownell else 64656c1e26d75008d39f1067f453719857a81109d9fDavid Brownell temp |= 0x0002; /* no power switching */ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// re-enable when we support USB_PORT_FEAT_INDICATOR below. 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HCS_INDICATOR (ehci->hcs_params)) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= 0x0080; /* per-port indicators (LEDs) */ 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 652fd05e720099e8eeddb378305d1a41c1445344b91Al Viro desc->wHubCharacteristics = cpu_to_le16(temp); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ehci_hub_control ( 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_hcd *hcd, 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 typeReq, 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wValue, 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wIndex, 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 wLength 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) { 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ehci_hcd *ehci = hcd_to_ehci (hcd); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ports = HCS_N_PORTS (ehci->hcs_params); 667383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern u32 __iomem *status_reg = &ehci->regs->port_status[ 668383975d765523a56dc43a6cd6d52e9b376800cf2Alan Stern (wIndex & 0xff) - 1]; 669331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du u32 __iomem *hostpc_reg = NULL; 670331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du u32 temp, temp1, status; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 673f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell unsigned selector; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HCS_INDICATOR may say we can change LEDs to off/amber/green. 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (track current state ourselves) ... blink for diagnostics, 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * power, "this is the one", etc. EHCI spec supports this. 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 682331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du if (ehci->has_hostpc) 683331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs 684331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du + HOSTPC0 + 4 * ((wIndex & 0xff) - 1)); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&ehci->lock, flags); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (typeReq) { 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearHubFeature: 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case C_HUB_LOCAL_POWER: 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case C_HUB_OVER_CURRENT: 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no hub-wide feature/status flags */ 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ClearPortFeature: 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!wIndex || wIndex > ports) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wIndex--; 701e6316565e568b3b5733be10cfca3c27259bef499Alan Stern temp = ehci_readl(ehci, status_reg); 702625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern 703625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern /* 704625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * Even if OWNER is set, so the port is owned by the 705625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * companion controller, khubd needs to be able to clear 706625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * the port-change status bits (especially 707749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern * USB_PORT_STAT_C_CONNECTION). 708625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern */ 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_ENABLE: 712e6316565e568b3b5733be10cfca3c27259bef499Alan Stern ehci_writel(ehci, temp & ~PORT_PE, status_reg); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_C_ENABLE: 715083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, 716e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & PORT_RESET) 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 721f8aeb3bb8657b207895aa10f75e63f2c48d08985David Brownell if (ehci->no_selective_suspend) 722f8aeb3bb8657b207895aa10f75e63f2c48d08985David Brownell break; 72383722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin#ifdef CONFIG_USB_OTG 72483722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin if ((hcd->self.otg_port == (wIndex + 1)) 72583722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin && hcd->self.b_hnp_enable) { 7266e13c6505cdff9766d5268ffb8c972c1a2f996e6Heikki Krogerus otg_start_hnp(ehci->transceiver->otg); 72783722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin break; 72883722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin } 72983722bc9430424de1614ff31696f73a40b3d81a9Anatolij Gustschin#endif 73016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (!(temp & PORT_SUSPEND)) 73116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern break; 73216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if ((temp & PORT_PE) == 0) 73316032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern goto error; 73416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern 73516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* clear phy low-power mode before resume */ 73616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern if (hostpc_reg) { 73716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern temp1 = ehci_readl(ehci, hostpc_reg); 73816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, 739eab80de01cb398419ef3305f35abcb367c647c8bAlek Du hostpc_reg); 74016032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern spin_unlock_irqrestore(&ehci->lock, flags); 74116032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern msleep(5);/* wait to leave low-power mode */ 74216032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern spin_lock_irqsave(&ehci->lock, flags); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74416032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern /* resume signaling for 20 msec */ 74516032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); 74616032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci_writel(ehci, temp | PORT_RESUME, status_reg); 74716032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern ehci->reset_done[wIndex] = jiffies 74816032c4f5b291af541e9114a09ea20ff5a0dc474Alan Stern + msecs_to_jiffies(20); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_C_SUSPEND: 751d1f114d12bb4db3147e1b1342ae31083c5a79c84Alan Stern clear_bit(wIndex, &ehci->port_c_suspend); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_POWER: 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HCS_PPC (ehci->hcs_params)) 755083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, 756083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt temp & ~(PORT_RWC_BITS | PORT_POWER), 757e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_C_CONNECTION: 76048f24970144479c29b8cee6d2e1dbedf6dcf9cfbAlek Du if (ehci->has_lpm) { 76148f24970144479c29b8cee6d2e1dbedf6dcf9cfbAlek Du /* clear PORTSC bits on disconnect */ 76248f24970144479c29b8cee6d2e1dbedf6dcf9cfbAlek Du temp &= ~PORT_LPM; 76348f24970144479c29b8cee6d2e1dbedf6dcf9cfbAlek Du temp &= ~PORT_DEV_ADDR; 76448f24970144479c29b8cee6d2e1dbedf6dcf9cfbAlek Du } 765083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, 766e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_C_OVER_CURRENT: 769083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, 770e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_C_RESET: 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* GetPortStatus clears reset */ 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 778083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubDescriptor: 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetHubStatus: 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no hub-wide feature/status flags */ 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset (buf, 0, 4); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //cpu_to_le32s ((u32 *) buf); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GetPortStatus: 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!wIndex || wIndex > ports) 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wIndex--; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = 0; 794e6316565e568b3b5733be10cfca3c27259bef499Alan Stern temp = ehci_readl(ehci, status_reg); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // wPortChange bits 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & PORT_CSC) 798749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_C_CONNECTION << 16; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & PORT_PEC) 800749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_C_ENABLE << 16; 801756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer 802756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer if ((temp & PORT_OCC) && !ignore_oc){ 803749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_C_OVERCURRENT << 16; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 805756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer /* 806756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer * Hubs should disable port power on over-current. 807756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer * However, not all EHCI implementations do this 808756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer * automatically, even if they _do_ support per-port 809756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer * power switching; they're allowed to just limit the 810756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer * current. khubd will turn the power back on. 811756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer */ 81281463c1d707186adbbe534016cd1249edeab0dacSergei Shtylyov if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { 813756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer ehci_writel(ehci, 814756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer temp & ~(PORT_RWC_BITS | PORT_POWER), 815756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer status_reg); 81681463c1d707186adbbe534016cd1249edeab0dacSergei Shtylyov temp = ehci_readl(ehci, status_reg); 817756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer } 818756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer } 819756aa6b3d536afe85e151138cb03a293998887b3Christian Engelmayer 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* whoever resumes must GetPortStatus to complete it!! */ 821629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern if (temp & PORT_RESUME) { 822629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern 823629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern /* Remote Wakeup received? */ 824629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern if (!ehci->reset_done[wIndex]) { 825629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern /* resume signaling for 20 msec */ 826629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci->reset_done[wIndex] = jiffies 827629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern + msecs_to_jiffies(20); 828629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern /* check the port again */ 829629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern mod_timer(&ehci_to_hcd(ehci)->rh_timer, 830629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci->reset_done[wIndex]); 831629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern } 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 833629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern /* resume completed? */ 834629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern else if (time_after_eq(jiffies, 835629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci->reset_done[wIndex])) { 836eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern clear_bit(wIndex, &ehci->suspended_ports); 837d1f114d12bb4db3147e1b1342ae31083c5a79c84Alan Stern set_bit(wIndex, &ehci->port_c_suspend); 838629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci->reset_done[wIndex] = 0; 839629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern 840629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern /* stop resume signaling */ 841629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern temp = ehci_readl(ehci, status_reg); 842629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci_writel(ehci, 843e6316565e568b3b5733be10cfca3c27259bef499Alan Stern temp & ~(PORT_RWC_BITS | PORT_RESUME), 844e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 845a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern clear_bit(wIndex, &ehci->resuming_ports); 846629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern retval = handshake(ehci, status_reg, 847083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt PORT_RESUME, 0, 2000 /* 2msec */); 848629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern if (retval != 0) { 849629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci_err(ehci, 850629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern "port %d resume error %d\n", 851629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern wIndex + 1, retval); 852629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern goto error; 853629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern } 854629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* whoever resets must GetPortStatus to complete it!! */ 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((temp & PORT_RESET) 860629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern && time_after_eq(jiffies, 861629e4427aa817d5c9f11885420abf54b8f5967dcAlan Stern ehci->reset_done[wIndex])) { 862749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_C_RESET << 16; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci->reset_done [wIndex] = 0; 864a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern clear_bit(wIndex, &ehci->resuming_ports); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* force reset to complete */ 867083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), 868e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 869c22fa3acbc2ef79ea57217643f6cd6d226963069David Brownell /* REVISIT: some hardware needs 550+ usec to clear 870c22fa3acbc2ef79ea57217643f6cd6d226963069David Brownell * this bit; seems too long to spin routinely... 871c22fa3acbc2ef79ea57217643f6cd6d226963069David Brownell */ 872e6316565e568b3b5733be10cfca3c27259bef499Alan Stern retval = handshake(ehci, status_reg, 8736307e0961205c50a8a9b6e8e3e4dfd178a944ba9Dinh Nguyen PORT_RESET, 0, 1000); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval != 0) { 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_err (ehci, "port %d reset error %d\n", 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wIndex + 1, retval); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see what we found out */ 881e6316565e568b3b5733be10cfca3c27259bef499Alan Stern temp = check_reset_complete (ehci, wIndex, status_reg, 882e6316565e568b3b5733be10cfca3c27259bef499Alan Stern ehci_readl(ehci, status_reg)); 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 885a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern if (!(temp & (PORT_RESUME|PORT_RESET))) { 886eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern ehci->reset_done[wIndex] = 0; 887a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern clear_bit(wIndex, &ehci->resuming_ports); 888a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern } 889eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern 89057e06c11372eccf5acebdd4664eb025fee76c561Alan Stern /* transfer dedicated ports to the companion hc */ 89157e06c11372eccf5acebdd4664eb025fee76c561Alan Stern if ((temp & PORT_CONNECT) && 89257e06c11372eccf5acebdd4664eb025fee76c561Alan Stern test_bit(wIndex, &ehci->companion_ports)) { 89357e06c11372eccf5acebdd4664eb025fee76c561Alan Stern temp &= ~PORT_RWC_BITS; 89457e06c11372eccf5acebdd4664eb025fee76c561Alan Stern temp |= PORT_OWNER; 89557e06c11372eccf5acebdd4664eb025fee76c561Alan Stern ehci_writel(ehci, temp, status_reg); 89657e06c11372eccf5acebdd4664eb025fee76c561Alan Stern ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1); 89757e06c11372eccf5acebdd4664eb025fee76c561Alan Stern temp = ehci_readl(ehci, status_reg); 89857e06c11372eccf5acebdd4664eb025fee76c561Alan Stern } 89957e06c11372eccf5acebdd4664eb025fee76c561Alan Stern 900625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern /* 901625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * Even if OWNER is set, there's no harm letting khubd 902625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * see the wPortStatus values (they should all be 0 except 903625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern * for PORT_POWER anyway). 904625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern */ 905625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern 906625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern if (temp & PORT_CONNECT) { 907749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_CONNECTION; 908625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern // status may be from integrated TT 909331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du if (ehci->has_hostpc) { 910331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du temp1 = ehci_readl(ehci, hostpc_reg); 911331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du status |= ehci_port_speed(ehci, temp1); 912331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du } else 913331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du status |= ehci_port_speed(ehci, temp); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 915625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern if (temp & PORT_PE) 916749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_ENABLE; 917eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern 918eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern /* maybe the port was unsuspended without our knowledge */ 919eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern if (temp & (PORT_SUSPEND|PORT_RESUME)) { 920749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_SUSPEND; 921eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern } else if (test_bit(wIndex, &ehci->suspended_ports)) { 922eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern clear_bit(wIndex, &ehci->suspended_ports); 923a448e4dc25303fe551e4dafe16c8c7c34f1b9d82Alan Stern clear_bit(wIndex, &ehci->resuming_ports); 924eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern ehci->reset_done[wIndex] = 0; 925eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern if (temp & PORT_PE) 926eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern set_bit(wIndex, &ehci->port_c_suspend); 927eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern } 928eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern 929625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern if (temp & PORT_OC) 930749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_OVERCURRENT; 931625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern if (temp & PORT_RESET) 932749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_RESET; 933625b5c9a0069ef1b61feb3ce599b39f1b04b5666Alan Stern if (temp & PORT_POWER) 934749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_POWER; 935d1f114d12bb4db3147e1b1342ae31083c5a79c84Alan Stern if (test_bit(wIndex, &ehci->port_c_suspend)) 936749da5f82fe33ff68dd4aa1a5e35cd9aa6246dabAlan Stern status |= USB_PORT_STAT_C_SUSPEND << 16; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9389776afc8b3dc487557f3f576002520f59be334e6David Brownell#ifndef VERBOSE_DEBUG 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & ~0xffff) /* only if wPortChange is interesting */ 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg_port (ehci, "GetStatus", wIndex + 1, temp); 942a5abdeafedf722b0f3f357f4a23089a686b1b80dHarvey Harrison put_unaligned_le32(status, buf); 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetHubFeature: 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case C_HUB_LOCAL_POWER: 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case C_HUB_OVER_CURRENT: 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no hub-wide feature/status flags */ 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SetPortFeature: 955f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell selector = wIndex >> 8; 956f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell wIndex &= 0xff; 9578d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel if (unlikely(ehci->debug)) { 9588d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel /* If the debug port is active any port 9598d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel * feature requests should get denied */ 9608d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel if (wIndex == HCS_DEBUG_PORT(ehci->hcs_params) && 9618d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel (readl(&ehci->debug->control) & DBGP_ENABLED)) { 9628d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel retval = -ENODEV; 9638d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel goto error_exit; 9648d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel } 9658d053c79f22462f55c02c8083580730b922cf7b4Jason Wessel } 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!wIndex || wIndex > ports) 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wIndex--; 969e6316565e568b3b5733be10cfca3c27259bef499Alan Stern temp = ehci_readl(ehci, status_reg); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & PORT_OWNER) 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97310f6524a8ef1413a8cbd952673997013183fe2a9David Brownell temp &= ~PORT_RWC_BITS; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (wValue) { 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_SUSPEND: 976f8aeb3bb8657b207895aa10f75e63f2c48d08985David Brownell if (ehci->no_selective_suspend) 977f8aeb3bb8657b207895aa10f75e63f2c48d08985David Brownell break; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((temp & PORT_PE) == 0 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (temp & PORT_RESET) != 0) 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 981b9df794258de24d10b0616634d4c30d8b6e9d381Alek Du 982331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du /* After above check the port must be connected. 983331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du * Set appropriate bit thus could put phy into low power 984331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du * mode if we have hostpc feature 985331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du */ 986b9df794258de24d10b0616634d4c30d8b6e9d381Alek Du temp &= ~PORT_WKCONN_E; 987b9df794258de24d10b0616634d4c30d8b6e9d381Alek Du temp |= PORT_WKDISC_E | PORT_WKOC_E; 988b9df794258de24d10b0616634d4c30d8b6e9d381Alek Du ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); 989331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du if (hostpc_reg) { 990b9df794258de24d10b0616634d4c30d8b6e9d381Alek Du spin_unlock_irqrestore(&ehci->lock, flags); 991331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du msleep(5);/* 5ms for HCD enter low pwr mode */ 992b9df794258de24d10b0616634d4c30d8b6e9d381Alek Du spin_lock_irqsave(&ehci->lock, flags); 993331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du temp1 = ehci_readl(ehci, hostpc_reg); 994331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du ehci_writel(ehci, temp1 | HOSTPC_PHCD, 995331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du hostpc_reg); 996331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du temp1 = ehci_readl(ehci, hostpc_reg); 997331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", 998331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du wIndex, (temp1 & HOSTPC_PHCD) ? 999331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du "succeeded" : "failed"); 1000331ac6b288d9f3689514ced1878041fb0df7e13cAlek Du } 1001eafe5b99f2135488b21cf17a262c54997c44f784Alan Stern set_bit(wIndex, &ehci->suspended_ports); 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_POWER: 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (HCS_PPC (ehci->hcs_params)) 1005083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_writel(ehci, temp | PORT_POWER, 1006e6316565e568b3b5733be10cfca3c27259bef499Alan Stern status_reg); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_PORT_FEAT_RESET: 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & PORT_RESUME) 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* line status bits may report this as low speed, 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which can be fine if this root hub has a 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transaction translator built in. 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !ehci_is_TDI(ehci) 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && PORT_USB11 (temp)) { 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_dbg (ehci, 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "port %d low speed --> companion\n", 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wIndex + 1); 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= PORT_OWNER; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci_vdbg (ehci, "port %d reset\n", wIndex + 1); 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp |= PORT_RESET; 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp &= ~PORT_PE; 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * caller must wait, then call GetPortStatus 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 spec says 50 ms resets on root 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ehci->reset_done [wIndex] = jiffies 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + msecs_to_jiffies (50); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1034e6316565e568b3b5733be10cfca3c27259bef499Alan Stern ehci_writel(ehci, temp, status_reg); 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1036f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell 1037f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell /* For downstream facing ports (these): one hub port is put 1038f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell * into test mode according to USB2 11.24.2.13, then the hub 1039f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell * must be reset (which for root hub now means rmmod+modprobe, 1040f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell * or else system reboot). See EHCI 2.3.9 and 4.14 for info 1041f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell * about the EHCI-specific stuff. 1042f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell */ 1043f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell case USB_PORT_FEAT_TEST: 1044f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell if (!selector || selector > 5) 1045f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell goto error; 1046f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell ehci_quiesce(ehci); 104777636c86a600b83de01719efad83567e46d7e8ceBoris Todorov 104877636c86a600b83de01719efad83567e46d7e8ceBoris Todorov /* Put all enabled ports into suspend */ 104977636c86a600b83de01719efad83567e46d7e8ceBoris Todorov while (ports--) { 105077636c86a600b83de01719efad83567e46d7e8ceBoris Todorov u32 __iomem *sreg = 105177636c86a600b83de01719efad83567e46d7e8ceBoris Todorov &ehci->regs->port_status[ports]; 105277636c86a600b83de01719efad83567e46d7e8ceBoris Todorov 105377636c86a600b83de01719efad83567e46d7e8ceBoris Todorov temp = ehci_readl(ehci, sreg) & ~PORT_RWC_BITS; 105477636c86a600b83de01719efad83567e46d7e8ceBoris Todorov if (temp & PORT_PE) 105577636c86a600b83de01719efad83567e46d7e8ceBoris Todorov ehci_writel(ehci, temp | PORT_SUSPEND, 105677636c86a600b83de01719efad83567e46d7e8ceBoris Todorov sreg); 105777636c86a600b83de01719efad83567e46d7e8ceBoris Todorov } 1058f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell ehci_halt(ehci); 105977636c86a600b83de01719efad83567e46d7e8ceBoris Todorov temp = ehci_readl(ehci, status_reg); 1060f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell temp |= selector << 16; 1061e6316565e568b3b5733be10cfca3c27259bef499Alan Stern ehci_writel(ehci, temp, status_reg); 1062f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell break; 1063f0d7f27351058284f62ab4848909373c2d1f5ce8David Brownell 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1067083522d76662cda71328df1f3d75e5a9057c7c9fBenjamin Herrenschmidt ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* "stall" on error */ 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EPIPE; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10758d053c79f22462f55c02c8083580730b922cf7b4Jason Wesselerror_exit: 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&ehci->lock, flags); 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 107990da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao 10805407a3c3d942e75d4d123d213fd692bce5acc961Felipe Balbistatic void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, 10815407a3c3d942e75d4d123d213fd692bce5acc961Felipe Balbi int portnum) 108290da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao{ 108390da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao struct ehci_hcd *ehci = hcd_to_ehci(hcd); 108490da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao 108590da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao if (ehci_is_TDI(ehci)) 108690da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao return; 108790da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao set_owner(ehci, --portnum, PORT_OWNER); 108890da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao} 108990da096ee46b682011b7d549e52b81cf9742e60bBalaji Rao 10905407a3c3d942e75d4d123d213fd692bce5acc961Felipe Balbistatic int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd, 10915407a3c3d942e75d4d123d213fd692bce5acc961Felipe Balbi int portnum) 10923a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern{ 10933a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern struct ehci_hcd *ehci = hcd_to_ehci(hcd); 10943a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern u32 __iomem *reg; 10953a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern 10963a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern if (ehci_is_TDI(ehci)) 10973a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern return 0; 10983a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern reg = &ehci->regs->port_status[portnum - 1]; 10993a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern return ehci_readl(ehci, reg) & PORT_OWNER; 11003a31155cfff0935e4b178f3dca733d2d60d2eb8dAlan Stern} 1101