|
@@ -2622,9 +2622,6 @@ static bool use_new_scheme(struct usb_device *udev, int retry)
|
|
return USE_NEW_SCHEME(retry);
|
|
return USE_NEW_SCHEME(retry);
|
|
}
|
|
}
|
|
|
|
|
|
-static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
|
|
- struct usb_device *udev, unsigned int delay, bool warm);
|
|
|
|
-
|
|
|
|
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
|
|
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
|
|
* Port worm reset is required to recover
|
|
* Port worm reset is required to recover
|
|
*/
|
|
*/
|
|
@@ -2712,44 +2709,6 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void hub_port_finish_reset(struct usb_hub *hub, int port1,
|
|
|
|
- struct usb_device *udev, int *status)
|
|
|
|
-{
|
|
|
|
- switch (*status) {
|
|
|
|
- case 0:
|
|
|
|
- /* TRSTRCY = 10 ms; plus some extra */
|
|
|
|
- msleep(10 + 40);
|
|
|
|
- if (udev) {
|
|
|
|
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
|
|
|
-
|
|
|
|
- update_devnum(udev, 0);
|
|
|
|
- /* The xHC may think the device is already reset,
|
|
|
|
- * so ignore the status.
|
|
|
|
- */
|
|
|
|
- if (hcd->driver->reset_device)
|
|
|
|
- hcd->driver->reset_device(hcd, udev);
|
|
|
|
- }
|
|
|
|
- /* FALL THROUGH */
|
|
|
|
- case -ENOTCONN:
|
|
|
|
- case -ENODEV:
|
|
|
|
- usb_clear_port_feature(hub->hdev,
|
|
|
|
- port1, USB_PORT_FEAT_C_RESET);
|
|
|
|
- if (hub_is_superspeed(hub->hdev)) {
|
|
|
|
- usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
- USB_PORT_FEAT_C_BH_PORT_RESET);
|
|
|
|
- usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
- USB_PORT_FEAT_C_PORT_LINK_STATE);
|
|
|
|
- usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
- USB_PORT_FEAT_C_CONNECTION);
|
|
|
|
- }
|
|
|
|
- if (udev)
|
|
|
|
- usb_set_device_state(udev, *status
|
|
|
|
- ? USB_STATE_NOTATTACHED
|
|
|
|
- : USB_STATE_DEFAULT);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
|
|
/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
|
|
static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
struct usb_device *udev, unsigned int delay, bool warm)
|
|
struct usb_device *udev, unsigned int delay, bool warm)
|
|
@@ -2773,13 +2732,10 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
* If the caller hasn't explicitly requested a warm reset,
|
|
* If the caller hasn't explicitly requested a warm reset,
|
|
* double check and see if one is needed.
|
|
* double check and see if one is needed.
|
|
*/
|
|
*/
|
|
- status = hub_port_status(hub, port1,
|
|
|
|
- &portstatus, &portchange);
|
|
|
|
- if (status < 0)
|
|
|
|
- goto done;
|
|
|
|
-
|
|
|
|
- if (hub_port_warm_reset_required(hub, port1, portstatus))
|
|
|
|
- warm = true;
|
|
|
|
|
|
+ if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
|
|
|
|
+ if (hub_port_warm_reset_required(hub, port1,
|
|
|
|
+ portstatus))
|
|
|
|
+ warm = true;
|
|
}
|
|
}
|
|
clear_bit(port1, hub->warm_reset_bits);
|
|
clear_bit(port1, hub->warm_reset_bits);
|
|
|
|
|
|
@@ -2805,11 +2761,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
|
|
|
|
/* Check for disconnect or reset */
|
|
/* Check for disconnect or reset */
|
|
if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
|
|
if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
|
|
- hub_port_finish_reset(hub, port1, udev, &status);
|
|
|
|
|
|
+ usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
+ USB_PORT_FEAT_C_RESET);
|
|
|
|
|
|
if (!hub_is_superspeed(hub->hdev))
|
|
if (!hub_is_superspeed(hub->hdev))
|
|
goto done;
|
|
goto done;
|
|
|
|
|
|
|
|
+ usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
+ USB_PORT_FEAT_C_BH_PORT_RESET);
|
|
|
|
+ usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
|
|
|
|
+ usb_clear_port_feature(hub->hdev, port1,
|
|
|
|
+ USB_PORT_FEAT_C_CONNECTION);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* If a USB 3.0 device migrates from reset to an error
|
|
* If a USB 3.0 device migrates from reset to an error
|
|
* state, re-issue the warm reset.
|
|
* state, re-issue the warm reset.
|
|
@@ -2842,6 +2806,26 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
|
|
dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
|
|
|
|
|
|
done:
|
|
done:
|
|
|
|
+ if (status == 0) {
|
|
|
|
+ /* TRSTRCY = 10 ms; plus some extra */
|
|
|
|
+ msleep(10 + 40);
|
|
|
|
+ if (udev) {
|
|
|
|
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
|
|
|
+
|
|
|
|
+ update_devnum(udev, 0);
|
|
|
|
+ /* The xHC may think the device is already reset,
|
|
|
|
+ * so ignore the status.
|
|
|
|
+ */
|
|
|
|
+ if (hcd->driver->reset_device)
|
|
|
|
+ hcd->driver->reset_device(hcd, udev);
|
|
|
|
+
|
|
|
|
+ usb_set_device_state(udev, USB_STATE_DEFAULT);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (udev)
|
|
|
|
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!hub_is_superspeed(hub->hdev))
|
|
if (!hub_is_superspeed(hub->hdev))
|
|
up_read(&ehci_cf_port_reset_rwsem);
|
|
up_read(&ehci_cf_port_reset_rwsem);
|
|
|
|
|