| From 77e05bb8ebc2487f8bd850acb5e383265364ca95 Mon Sep 17 00:00:00 2001 |
| From: Guoqing Zhang <guoqing.zhang@intel.com> |
| Date: Fri, 7 Apr 2017 17:56:52 +0300 |
| Subject: [PATCH 179/286] usb: xhci: Add helper function xhci_disable_slot(). |
| |
| Refactoring slot disable related code into a helper |
| function xhci_disable_slot() which can be used when |
| enabling test mode. |
| |
| Signed-off-by: Guoqing Zhang <guoqing.zhang@intel.com> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| (cherry picked from commit f9e609b82479ef48469d42b022b0951abc00dcd1) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/usb/host/xhci.c | 49 ++++++++++++++++++++++++++++++------------------ |
| drivers/usb/host/xhci.h | 2 + |
| 2 files changed, 33 insertions(+), 18 deletions(-) |
| |
| --- a/drivers/usb/host/xhci.c |
| +++ b/drivers/usb/host/xhci.c |
| @@ -3564,8 +3564,6 @@ void xhci_free_dev(struct usb_hcd *hcd, |
| { |
| struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
| struct xhci_virt_device *virt_dev; |
| - unsigned long flags; |
| - u32 state; |
| int i, ret; |
| struct xhci_command *command; |
| |
| @@ -3600,30 +3598,50 @@ void xhci_free_dev(struct usb_hcd *hcd, |
| del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); |
| } |
| |
| + xhci_disable_slot(xhci, command, udev->slot_id); |
| + /* |
| + * Event command completion handler will free any data structures |
| + * associated with the slot. XXX Can free sleep? |
| + */ |
| +} |
| + |
| +int xhci_disable_slot(struct xhci_hcd *xhci, struct xhci_command *command, |
| + u32 slot_id) |
| +{ |
| + unsigned long flags; |
| + u32 state; |
| + int ret = 0; |
| + struct xhci_virt_device *virt_dev; |
| + |
| + virt_dev = xhci->devs[slot_id]; |
| + if (!virt_dev) |
| + return -EINVAL; |
| + if (!command) |
| + command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); |
| + if (!command) |
| + return -ENOMEM; |
| + |
| spin_lock_irqsave(&xhci->lock, flags); |
| /* Don't disable the slot if the host controller is dead. */ |
| state = readl(&xhci->op_regs->status); |
| if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || |
| (xhci->xhc_state & XHCI_STATE_HALTED)) { |
| - xhci_free_virt_device(xhci, udev->slot_id); |
| + xhci_free_virt_device(xhci, slot_id); |
| spin_unlock_irqrestore(&xhci->lock, flags); |
| kfree(command); |
| - return; |
| + return ret; |
| } |
| |
| - if (xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, |
| - udev->slot_id)) { |
| + ret = xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, |
| + slot_id); |
| + if (ret) { |
| spin_unlock_irqrestore(&xhci->lock, flags); |
| xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); |
| - return; |
| + return ret; |
| } |
| xhci_ring_cmd_db(xhci); |
| spin_unlock_irqrestore(&xhci->lock, flags); |
| - |
| - /* |
| - * Event command completion handler will free any data structures |
| - * associated with the slot. XXX Can free sleep? |
| - */ |
| + return ret; |
| } |
| |
| /* |
| @@ -3730,15 +3748,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, |
| |
| disable_slot: |
| /* Disable slot, if we can do it without mem alloc */ |
| - spin_lock_irqsave(&xhci->lock, flags); |
| kfree(command->completion); |
| command->completion = NULL; |
| command->status = 0; |
| - if (!xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, |
| - udev->slot_id)) |
| - xhci_ring_cmd_db(xhci); |
| - spin_unlock_irqrestore(&xhci->lock, flags); |
| - return 0; |
| + return xhci_disable_slot(xhci, command, udev->slot_id); |
| } |
| |
| /* |
| --- a/drivers/usb/host/xhci.h |
| +++ b/drivers/usb/host/xhci.h |
| @@ -2021,6 +2021,8 @@ void xhci_shutdown(struct usb_hcd *hcd); |
| int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); |
| void xhci_init_driver(struct hc_driver *drv, |
| const struct xhci_driver_overrides *over); |
| +int xhci_disable_slot(struct xhci_hcd *xhci, |
| + struct xhci_command *command, u32 slot_id); |
| |
| #ifdef CONFIG_PM |
| int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); |