diff options
author | Andiry Xu <andiry.xu@amd.com> | 2010-10-14 10:22:48 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-22 13:22:11 -0400 |
commit | f0615c45ce5feb141c1172480c5198d4b8d25436 (patch) | |
tree | 9c16dbd56591297d94286f7f3e12b80d07ec28a8 /drivers/usb/host | |
parent | 64927730c66333c9d5987aa72a0e6d44ed91cec7 (diff) |
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: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 44 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
3 files changed, 41 insertions, 7 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index f7efe025beda..aefc3496376a 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -152,7 +152,7 @@ static const struct hc_driver xhci_pci_hc_driver = { | |||
152 | .reset_bandwidth = xhci_reset_bandwidth, | 152 | .reset_bandwidth = xhci_reset_bandwidth, |
153 | .address_device = xhci_address_device, | 153 | .address_device = xhci_address_device, |
154 | .update_hub_device = xhci_update_hub_device, | 154 | .update_hub_device = xhci_update_hub_device, |
155 | .reset_device = xhci_reset_device, | 155 | .reset_device = xhci_discover_or_reset_device, |
156 | 156 | ||
157 | /* | 157 | /* |
158 | * scheduling support | 158 | * scheduling support |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0bec04070334..7928af5c91cb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -1943,8 +1943,13 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, | |||
1943 | * Wait for the Reset Device command to finish. Remove all structures | 1943 | * Wait for the Reset Device command to finish. Remove all structures |
1944 | * associated with the endpoints that were disabled. Clear the input device | 1944 | * associated with the endpoints that were disabled. Clear the input device |
1945 | * structure? Cache the rings? Reset the control endpoint 0 max packet size? | 1945 | * structure? Cache the rings? Reset the control endpoint 0 max packet size? |
1946 | * | ||
1947 | * If the virt_dev to be reset does not exist or does not match the udev, | ||
1948 | * it means the device is lost, possibly due to the xHC restore error and | ||
1949 | * re-initialization during S3/S4. In this case, call xhci_alloc_dev() to | ||
1950 | * re-allocate the device. | ||
1946 | */ | 1951 | */ |
1947 | int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev) | 1952 | int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) |
1948 | { | 1953 | { |
1949 | int ret, i; | 1954 | int ret, i; |
1950 | unsigned long flags; | 1955 | unsigned long flags; |
@@ -1955,12 +1960,36 @@ int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev) | |||
1955 | int timeleft; | 1960 | int timeleft; |
1956 | int last_freed_endpoint; | 1961 | int last_freed_endpoint; |
1957 | 1962 | ||
1958 | ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); | 1963 | ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__); |
1959 | if (ret <= 0) | 1964 | if (ret <= 0) |
1960 | return ret; | 1965 | return ret; |
1961 | xhci = hcd_to_xhci(hcd); | 1966 | xhci = hcd_to_xhci(hcd); |
1962 | slot_id = udev->slot_id; | 1967 | slot_id = udev->slot_id; |
1963 | virt_dev = xhci->devs[slot_id]; | 1968 | virt_dev = xhci->devs[slot_id]; |
1969 | if (!virt_dev) { | ||
1970 | xhci_dbg(xhci, "The device to be reset with slot ID %u does " | ||
1971 | "not exist. Re-allocate the device\n", slot_id); | ||
1972 | ret = xhci_alloc_dev(hcd, udev); | ||
1973 | if (ret == 1) | ||
1974 | return 0; | ||
1975 | else | ||
1976 | return -EINVAL; | ||
1977 | } | ||
1978 | |||
1979 | if (virt_dev->udev != udev) { | ||
1980 | /* If the virt_dev and the udev does not match, this virt_dev | ||
1981 | * may belong to another udev. | ||
1982 | * Re-allocate the device. | ||
1983 | */ | ||
1984 | xhci_dbg(xhci, "The device to be reset with slot ID %u does " | ||
1985 | "not match the udev. Re-allocate the device\n", | ||
1986 | slot_id); | ||
1987 | ret = xhci_alloc_dev(hcd, udev); | ||
1988 | if (ret == 1) | ||
1989 | return 0; | ||
1990 | else | ||
1991 | return -EINVAL; | ||
1992 | } | ||
1964 | 1993 | ||
1965 | xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); | 1994 | xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); |
1966 | /* Allocate the command structure that holds the struct completion. | 1995 | /* 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) | |||
2176 | 2205 | ||
2177 | virt_dev = xhci->devs[udev->slot_id]; | 2206 | virt_dev = xhci->devs[udev->slot_id]; |
2178 | 2207 | ||
2179 | /* If this is a Set Address to an unconfigured device, setup ep 0 */ | 2208 | slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); |
2180 | if (!udev->config) | 2209 | /* |
2210 | * If this is the first Set Address since device plug-in or | ||
2211 | * virt_device realloaction after a resume with an xHCI power loss, | ||
2212 | * then set up the slot context. | ||
2213 | */ | ||
2214 | if (!slot_ctx->dev_info) | ||
2181 | xhci_setup_addressable_virt_dev(xhci, udev); | 2215 | xhci_setup_addressable_virt_dev(xhci, udev); |
2216 | /* Otherwise, update the control endpoint ring enqueue pointer. */ | ||
2182 | else | 2217 | else |
2183 | xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); | 2218 | xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); |
2184 | /* Otherwise, assume the core has the device configured how it wants */ | ||
2185 | xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); | 2219 | xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); |
2186 | xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); | 2220 | xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); |
2187 | 2221 | ||
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f03f140a7d9a..490409f918f2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1389,7 +1389,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); | |||
1389 | int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); | 1389 | int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); |
1390 | int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); | 1390 | int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); |
1391 | void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); | 1391 | void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); |
1392 | int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev); | 1392 | int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev); |
1393 | int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); | 1393 | int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); |
1394 | void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); | 1394 | void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); |
1395 | 1395 | ||