aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2011-04-27 06:07:54 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-02 19:42:54 -0400
commit5e467f6ebab151b2f0166e17348e5b85ae3c87fa (patch)
tree27d4d5ccb99c29d562d941b97513fe77979d1151 /drivers
parenta7114230f6bd925f1c734d8ca1c32c93bf956aed (diff)
usbcore: warm reset USB3 port in SS.Inactive state
Some USB3.0 devices go to SS.Inactive state when hot plug to USB3 ports. Warm reset the port to transition it to U0 state. This patch fixes the issue that Kingston USB3.0 flash drive can not be recognized when hot plug to USB3 port. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/hub.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 93035d862c63..79a58c3a2e2a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2151,6 +2151,42 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
2151 return status; 2151 return status;
2152} 2152}
2153 2153
2154/* Warm reset a USB3 protocol port */
2155static int hub_port_warm_reset(struct usb_hub *hub, int port)
2156{
2157 int ret;
2158 u16 portstatus, portchange;
2159
2160 if (!hub_is_superspeed(hub->hdev)) {
2161 dev_err(hub->intfdev, "only USB3 hub support warm reset\n");
2162 return -EINVAL;
2163 }
2164
2165 /* Warm reset the port */
2166 ret = set_port_feature(hub->hdev,
2167 port, USB_PORT_FEAT_BH_PORT_RESET);
2168 if (ret) {
2169 dev_err(hub->intfdev, "cannot warm reset port %d\n", port);
2170 return ret;
2171 }
2172
2173 msleep(20);
2174 ret = hub_port_status(hub, port, &portstatus, &portchange);
2175
2176 if (portchange & USB_PORT_STAT_C_RESET)
2177 clear_port_feature(hub->hdev, port, USB_PORT_FEAT_C_RESET);
2178
2179 if (portchange & USB_PORT_STAT_C_BH_RESET)
2180 clear_port_feature(hub->hdev, port,
2181 USB_PORT_FEAT_C_BH_PORT_RESET);
2182
2183 if (portchange & USB_PORT_STAT_C_LINK_STATE)
2184 clear_port_feature(hub->hdev, port,
2185 USB_PORT_FEAT_C_PORT_LINK_STATE);
2186
2187 return ret;
2188}
2189
2154/* Check if a port is power on */ 2190/* Check if a port is power on */
2155static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) 2191static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
2156{ 2192{
@@ -3519,6 +3555,16 @@ static void hub_events(void)
3519 USB_PORT_FEAT_C_PORT_CONFIG_ERROR); 3555 USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
3520 } 3556 }
3521 3557
3558 /* Warm reset a USB3 protocol port if it's in
3559 * SS.Inactive state.
3560 */
3561 if (hub_is_superspeed(hub->hdev) &&
3562 (portstatus & USB_PORT_STAT_LINK_STATE)
3563 == USB_SS_PORT_LS_SS_INACTIVE) {
3564 dev_dbg(hub_dev, "warm reset port %d\n", i);
3565 hub_port_warm_reset(hub, i);
3566 }
3567
3522 if (connect_change) 3568 if (connect_change)
3523 hub_port_connect_change(hub, i, 3569 hub_port_connect_change(hub, i,
3524 portstatus, portchange); 3570 portstatus, portchange);