summaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 8a819e853288..742c23826e17 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -121,7 +121,8 @@ int xhci_halt(struct xhci_hcd *xhci)
ret = xhci_handshake(&xhci->op_regs->status,
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
if (ret) {
- xhci_warn(xhci, "Host halt failed, %d\n", ret);
+ if (!(xhci->xhc_state & XHCI_STATE_DYING))
+ xhci_warn(xhci, "Host halt failed, %d\n", ret);
return ret;
}
@@ -180,7 +181,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us)
state = readl(&xhci->op_regs->status);
if (state == ~(u32)0) {
- xhci_warn(xhci, "Host not accessible, reset failed.\n");
+ if (!(xhci->xhc_state & XHCI_STATE_DYING))
+ xhci_warn(xhci, "Host not accessible, reset failed.\n");
return -ENODEV;
}
@@ -307,6 +309,7 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir)
return -EINVAL;
iman = readl(&ir->ir_set->iman);
+ iman &= ~IMAN_IP;
iman |= IMAN_IE;
writel(iman, &ir->ir_set->iman);
@@ -323,6 +326,7 @@ int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
return -EINVAL;
iman = readl(&ir->ir_set->iman);
+ iman &= ~IMAN_IP;
iman &= ~IMAN_IE;
writel(iman, &ir->ir_set->iman);
@@ -3930,8 +3934,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
* Obtaining a new device slot to inform the xHCI host that
* the USB device has been reset.
*/
- ret = xhci_disable_slot(xhci, udev->slot_id);
- xhci_free_virt_device(xhci, udev->slot_id);
+ ret = xhci_disable_and_free_slot(xhci, udev->slot_id);
if (!ret) {
ret = xhci_alloc_dev(hcd, udev);
if (ret == 1)
@@ -4088,7 +4091,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
xhci_disable_slot(xhci, udev->slot_id);
spin_lock_irqsave(&xhci->lock, flags);
- xhci_free_virt_device(xhci, udev->slot_id);
+ xhci_free_virt_device(xhci, virt_dev, udev->slot_id);
spin_unlock_irqrestore(&xhci->lock, flags);
}
@@ -4137,6 +4140,16 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
return 0;
}
+int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id)
+{
+ struct xhci_virt_device *vdev = xhci->devs[slot_id];
+ int ret;
+
+ ret = xhci_disable_slot(xhci, slot_id);
+ xhci_free_virt_device(xhci, vdev, slot_id);
+ return ret;
+}
+
/*
* Checks if we have enough host controller resources for the default control
* endpoint.
@@ -4243,8 +4256,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
return 1;
disable_slot:
- xhci_disable_slot(xhci, udev->slot_id);
- xhci_free_virt_device(xhci, udev->slot_id);
+ xhci_disable_and_free_slot(xhci, udev->slot_id);
return 0;
}
@@ -4380,8 +4392,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
dev_warn(&udev->dev, "Device not responding to setup %s.\n", act);
mutex_unlock(&xhci->mutex);
- ret = xhci_disable_slot(xhci, udev->slot_id);
- xhci_free_virt_device(xhci, udev->slot_id);
+ ret = xhci_disable_and_free_slot(xhci, udev->slot_id);
if (!ret) {
if (xhci_alloc_dev(hcd, udev) == 1)
xhci_setup_addressable_virt_dev(xhci, udev);