summaryrefslogtreecommitdiffstats
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.c124
1 files changed, 91 insertions, 33 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c020b094fe7..2a5d45b4cb1 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -491,7 +491,7 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
* Systems:
* Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820
*/
-bool xhci_compliance_mode_recovery_timer_quirk_check(void)
+static bool xhci_compliance_mode_recovery_timer_quirk_check(void)
{
const char *dmi_product_name, *dmi_sys_vendor;
@@ -653,6 +653,7 @@ int xhci_run(struct usb_hcd *hcd)
"Finished xhci_run for USB2 roothub");
return 0;
}
+EXPORT_SYMBOL_GPL(xhci_run);
static void xhci_only_stop_hcd(struct usb_hcd *hcd)
{
@@ -871,6 +872,8 @@ int xhci_suspend(struct xhci_hcd *xhci)
xhci_dbg(xhci, "%s: stopping port polling.\n", __func__);
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
+ clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+ del_timer_sync(&xhci->shared_hcd->rh_timer);
spin_lock_irq(&xhci->lock);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -927,6 +930,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
return rc;
}
+EXPORT_SYMBOL_GPL(xhci_suspend);
/*
* start xHC (not bus-specific)
@@ -1075,9 +1079,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
+ set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+ usb_hcd_poll_rh_status(xhci->shared_hcd);
return retval;
}
+EXPORT_SYMBOL_GPL(xhci_resume);
#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -2887,14 +2894,9 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
* issue a configure endpoint command later.
*/
if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
- struct xhci_command *command;
- /* Can't sleep if we're called from cleanup_halted_endpoint() */
- command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
- if (!command)
- return;
xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
"Queueing new dequeue state");
- xhci_queue_new_dequeue_state(xhci, command, udev->slot_id,
+ xhci_queue_new_dequeue_state(xhci, udev->slot_id,
ep_index, ep->stopped_stream, &deq_state);
} else {
/* Better hope no one uses the input context between now and the
@@ -3761,8 +3763,8 @@ disable_slot:
/*
* Issue an Address Device command and optionally send a corresponding
* SetAddress request to the device.
- * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so
- * we should only issue and wait on one address command at the same time.
+ * We should be protected by the usb_address0_mutex in hub_wq's hub_port_init,
+ * so we should only issue and wait on one address command at the same time.
*/
static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
enum xhci_setup_dev setup)
@@ -3971,13 +3973,21 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
int ret;
spin_lock_irqsave(&xhci->lock, flags);
- if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
+
+ virt_dev = xhci->devs[udev->slot_id];
+
+ /*
+ * virt_dev might not exists yet if xHC resumed from hibernate (S4) and
+ * xHC was re-initialized. Exit latency will be set later after
+ * hub_port_finish_reset() is done and xhci->devs[] are re-allocated
+ */
+
+ if (!virt_dev || max_exit_latency == virt_dev->current_mel) {
spin_unlock_irqrestore(&xhci->lock, flags);
return 0;
}
/* Attempt to issue an Evaluate Context command to change the MEL. */
- virt_dev = xhci->devs[udev->slot_id];
command = xhci->lpm_command;
ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
if (!ctrl_ctx) {
@@ -4895,6 +4905,76 @@ error:
kfree(xhci);
return retval;
}
+EXPORT_SYMBOL_GPL(xhci_gen_setup);
+
+static const struct hc_driver xhci_hc_driver = {
+ .description = "xhci-hcd",
+ .product_desc = "xHCI Host Controller",
+ .hcd_priv_size = sizeof(struct xhci_hcd *),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = xhci_irq,
+ .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = NULL, /* set in xhci_init_driver() */
+ .start = xhci_run,
+ .stop = xhci_stop,
+ .shutdown = xhci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = xhci_urb_enqueue,
+ .urb_dequeue = xhci_urb_dequeue,
+ .alloc_dev = xhci_alloc_dev,
+ .free_dev = xhci_free_dev,
+ .alloc_streams = xhci_alloc_streams,
+ .free_streams = xhci_free_streams,
+ .add_endpoint = xhci_add_endpoint,
+ .drop_endpoint = xhci_drop_endpoint,
+ .endpoint_reset = xhci_endpoint_reset,
+ .check_bandwidth = xhci_check_bandwidth,
+ .reset_bandwidth = xhci_reset_bandwidth,
+ .address_device = xhci_address_device,
+ .enable_device = xhci_enable_device,
+ .update_hub_device = xhci_update_hub_device,
+ .reset_device = xhci_discover_or_reset_device,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = xhci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_control = xhci_hub_control,
+ .hub_status_data = xhci_hub_status_data,
+ .bus_suspend = xhci_bus_suspend,
+ .bus_resume = xhci_bus_resume,
+
+ /*
+ * call back when device connected and addressed
+ */
+ .update_device = xhci_update_device,
+ .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
+ .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
+ .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
+ .find_raw_port_number = xhci_find_raw_port_number,
+};
+
+void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *))
+{
+ BUG_ON(!setup_fn);
+ *drv = xhci_hc_driver;
+ drv->reset = setup_fn;
+}
+EXPORT_SYMBOL_GPL(xhci_init_driver);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -4902,18 +4982,6 @@ MODULE_LICENSE("GPL");
static int __init xhci_hcd_init(void)
{
- int retval;
-
- retval = xhci_register_pci();
- if (retval < 0) {
- pr_debug("Problem registering PCI driver.\n");
- return retval;
- }
- retval = xhci_register_plat();
- if (retval < 0) {
- pr_debug("Problem registering platform driver.\n");
- goto unreg_pci;
- }
/*
* Check the compiler generated sizes of structures that must be laid
* out in specific ways for hardware access.
@@ -4932,15 +5000,5 @@ static int __init xhci_hcd_init(void)
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
return 0;
-unreg_pci:
- xhci_unregister_pci();
- return retval;
}
module_init(xhci_hcd_init);
-
-static void __exit xhci_hcd_cleanup(void)
-{
- xhci_unregister_pci();
- xhci_unregister_plat();
-}
-module_exit(xhci_hcd_cleanup);