[RFC] usb: Realloc xHCI structures after a hub is verified.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When there's an xHCI host power loss after a suspend from memory, the USB
core attempts to reset and verify the USB devices that are attached to the
system.  The xHCI driver has to reallocate those devices, since the
hardware lost all knowledge of them during the power loss.

When a hub is plugged in, and the host loses power, the xHCI hardware
structures are not updated to say the device is a hub.  This is usually
done in hub_configure() when the USB hub is detected.  That function is
skipped during a reset and verify by the USB core, since the core restores
the old configuration and alternate settings, and the hub driver has no
idea this happened.  This bug makes the xHCI host controller reject the
enumeration of low speed devices under the resumed hub.

Therefore, make the USB core re-setup the internal xHCI hub device
information by calling update_hub_device() after the alternate settings
have been re-installed.  usb_reset_and_verify_device() may be called as
part of a normal hub port resume from a bus resume event (instead of a
system resume event), and the re-setup may not be necessary.  However, we
can't tell the difference in finish_port_resume(), so unconditionally
re-setup the hub.  It will add a slight delay to port resume as the
xHCI Evaluate Context command completes.

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
---

Alan,

I'm not sure about the memory flags here.  usb_reset_and_verify_device()
will eventually trickle down to xhci_discover_or_reset_device(), which
uses GFP_KERNEL to reallocate the xHCI device structures.  Is this the
correct memory flag to use in this context?

Sarah


 drivers/usb/core/hub.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 27115b4..97bc556 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3621,6 +3621,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 {
 	struct usb_device		*parent_hdev = udev->parent;
 	struct usb_hub			*parent_hub;
+	struct usb_hub			*this_hub;
 	struct usb_hcd			*hcd = bus_to_hcd(udev->bus);
 	struct usb_device_descriptor	descriptor = udev->descriptor;
 	int 				i, ret = 0;
@@ -3724,6 +3725,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
 			goto re_enumerate;
 		}
 	}
+	/* If this is a re-verified hub, the xHCI driver will need to know, so
+	 * it can reallocate the hardware hub device information.
+	 */
+	if (udev->maxchild && hcd->driver->update_hub_device) {
+		this_hub = hdev_to_hub(udev);
+		if (!this_hub)
+			return 0;
+		ret = hcd->driver->update_hub_device(hcd, udev,
+				&this_hub->tt, GFP_KERNEL);
+		if (ret < 0)
+			goto re_enumerate;
+	}
 
 done:
 	return 0;
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux