Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0615c45 authored by Andiry Xu's avatar Andiry Xu Committed by Greg Kroah-Hartman
Browse files

USB: xHCI: change xhci_reset_device() to allocate new device



Rename xhci_reset_device() to xhci_discover_or_reset_device().
If xhci_discover_or_reset_device() is called to reset a device which does
not exist or does not match the udev, it calls xhci_alloc_dev() to
re-allocate the device.

This would prevent the reset device failure, possibly due to the xHC restore
error during S3/S4 resume.

Signed-off-by: default avatarAndiry Xu <andiry.xu@amd.com>
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 64927730
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
	.reset_bandwidth =	xhci_reset_bandwidth,
	.address_device =	xhci_address_device,
	.update_hub_device =	xhci_update_hub_device,
	.reset_device =		xhci_reset_device,
	.reset_device =		xhci_discover_or_reset_device,

	/*
	 * scheduling support
+39 −5
Original line number Diff line number Diff line
@@ -1943,8 +1943,13 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
 * Wait for the Reset Device command to finish.  Remove all structures
 * associated with the endpoints that were disabled.  Clear the input device
 * structure?  Cache the rings?  Reset the control endpoint 0 max packet size?
 *
 * If the virt_dev to be reset does not exist or does not match the udev,
 * it means the device is lost, possibly due to the xHC restore error and
 * re-initialization during S3/S4. In this case, call xhci_alloc_dev() to
 * re-allocate the device.
 */
int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
{
	int ret, i;
	unsigned long flags;
@@ -1955,12 +1960,36 @@ int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
	int timeleft;
	int last_freed_endpoint;

	ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
	ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__);
	if (ret <= 0)
		return ret;
	xhci = hcd_to_xhci(hcd);
	slot_id = udev->slot_id;
	virt_dev = xhci->devs[slot_id];
	if (!virt_dev) {
		xhci_dbg(xhci, "The device to be reset with slot ID %u does "
				"not exist. Re-allocate the device\n", slot_id);
		ret = xhci_alloc_dev(hcd, udev);
		if (ret == 1)
			return 0;
		else
			return -EINVAL;
	}

	if (virt_dev->udev != udev) {
		/* If the virt_dev and the udev does not match, this virt_dev
		 * may belong to another udev.
		 * Re-allocate the device.
		 */
		xhci_dbg(xhci, "The device to be reset with slot ID %u does "
				"not match the udev. Re-allocate the device\n",
				slot_id);
		ret = xhci_alloc_dev(hcd, udev);
		if (ret == 1)
			return 0;
		else
			return -EINVAL;
	}

	xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
	/* Allocate the command structure that holds the struct completion.
@@ -2176,12 +2205,17 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)

	virt_dev = xhci->devs[udev->slot_id];

	/* If this is a Set Address to an unconfigured device, setup ep 0 */
	if (!udev->config)
	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
	/*
	 * If this is the first Set Address since device plug-in or
	 * virt_device realloaction after a resume with an xHCI power loss,
	 * then set up the slot context.
	 */
	if (!slot_ctx->dev_info)
		xhci_setup_addressable_virt_dev(xhci, udev);
	/* Otherwise, update the control endpoint ring enqueue pointer. */
	else
		xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
	/* Otherwise, assume the core has the device configured how it wants */
	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);

+1 −1
Original line number Diff line number Diff line
@@ -1389,7 +1389,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);