From: Tung Nguyen <tunguyen@xxxxxxx> Currently, hcd->shared_hcd always creates and registers to the usb-core. If, for some reasons, USB3 downstream port is disabled, no roothub port for USB3.0 is found. This causes kernel to display an error: hub 2-0:1.0: config failed, hub doesn't have any ports! (err -19) This patch checks, creates and registers shared_hcd if USB3.0 downstream port is available. Signed-off-by: Tung Nguyen <tunguyen@xxxxxxx> Signed-off-by: Thang Q. Nguyen <tqnguyen@xxxxxxx> --- drivers/usb/host/xhci-mem.c | 2 +- drivers/usb/host/xhci-plat.c | 26 +++++++++++---------- drivers/usb/host/xhci.c | 54 ++++++++++++++++++++++++++++++++------------ 3 files changed, 54 insertions(+), 28 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 554a8a5..157d1e7 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1067,7 +1067,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci, struct usb_device *top_dev; struct usb_hcd *hcd; - if (udev->speed >= USB_SPEED_SUPER) + if (udev->speed >= USB_SPEED_SUPER && xhci->shared_hcd) hcd = xhci->shared_hcd; else hcd = xhci->main_hcd; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 6f03830..e812e3d 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -253,12 +253,6 @@ static int xhci_plat_probe(struct platform_device *pdev) xhci->clk = clk; xhci->main_hcd = hcd; - xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, - dev_name(&pdev->dev), hcd); - if (!xhci->shared_hcd) { - ret = -ENOMEM; - goto disable_clk; - } if (device_property_read_bool(sysdev, "usb2-lpm-disable")) xhci->quirks |= XHCI_HW_LPM_DISABLE; @@ -290,12 +284,20 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; - - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); - if (ret) - goto dealloc_usb2_hcd; + if (xhci->num_usb3_ports > 0) { + xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, + dev_name(&pdev->dev), hcd); + if (!xhci->shared_hcd) { + ret = -ENOMEM; + goto disable_clk; + } + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) + goto dealloc_usb2_hcd; + } device_enable_async_suspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 05104bd..4824bf6 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -417,12 +417,14 @@ static void compliance_mode_recovery(struct timer_list *t) i + 1); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Attempting compliance mode recovery"); - hcd = xhci->shared_hcd; + if (xhci->shared_hcd) { + hcd = xhci->shared_hcd; - if (hcd->state == HC_STATE_SUSPENDED) - usb_hcd_resume_root_hub(hcd); + if (hcd->state == HC_STATE_SUSPENDED) + usb_hcd_resume_root_hub(hcd); - usb_hcd_poll_rh_status(hcd); + usb_hcd_poll_rh_status(hcd); + } } } @@ -611,6 +613,18 @@ int xhci_run(struct usb_hcd *hcd) if (ret) xhci_free_command(xhci, command); } + /* + * Execute xhci_start() in case xhci->shared_hcd is not registered. + * If the xhci->shared_hcd doesn't exist, no one triggers to start + * the xhci which should be done before exitting run function + */ + if (!xhci->shared_hcd) { + if (xhci_start(xhci)) { + xhci_halt(xhci); + return -ENODEV; + } + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + } xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_run for USB2 roothub"); @@ -861,8 +875,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) if (!hcd->state) return 0; - if (hcd->state != HC_STATE_SUSPENDED || - xhci->shared_hcd->state != HC_STATE_SUSPENDED) + if (hcd->state != HC_STATE_SUSPENDED || (xhci->shared_hcd && + xhci->shared_hcd->state != HC_STATE_SUSPENDED)) return -EINVAL; xhci_dbc_suspend(xhci); @@ -875,12 +889,15 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) 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); + if (xhci->shared_hcd) { + 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); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + if (xhci->shared_hcd) + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); /* step 1: stop endpoint */ /* skipped assuming that port suspend has done */ @@ -961,7 +978,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) msleep(100); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + if (xhci->shared_hcd) + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); spin_lock_irq(&xhci->lock); if (xhci->quirks & XHCI_RESET_ON_RESUME) @@ -998,7 +1016,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Let the USB core know _both_ roothubs lost power. */ usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); - usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); + if (xhci->shared_hcd) + usb_root_hub_lost_power( + xhci->shared_hcd->self.root_hub); xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); @@ -1039,7 +1059,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) retval = xhci_run(secondary_hcd); } hcd->state = HC_STATE_SUSPENDED; - xhci->shared_hcd->state = HC_STATE_SUSPENDED; + if (xhci->shared_hcd) + xhci->shared_hcd->state = HC_STATE_SUSPENDED; goto done; } @@ -1068,7 +1089,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Resume root hubs only when have pending events. */ status = readl(&xhci->op_regs->status); if (status & STS_EINT) { - usb_hcd_resume_root_hub(xhci->shared_hcd); + if (xhci->shared_hcd) + usb_hcd_resume_root_hub(xhci->shared_hcd); usb_hcd_resume_root_hub(hcd); } } @@ -1087,8 +1109,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* Re-enable port polling. */ xhci_dbg(xhci, "%s: starting port polling.\n", __func__); - set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); - usb_hcd_poll_rh_status(xhci->shared_hcd); + if (xhci->shared_hcd) { + set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + usb_hcd_poll_rh_status(xhci->shared_hcd); + } set_bit(HCD_FLAG_POLL_RH, &hcd->flags); usb_hcd_poll_rh_status(hcd); -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html