xhci: prepare for operation w/o shared hcd
This patch prepares xhci for the following scenario: - If either of the root hubs has no ports, then omit shared hcd - Main hcd can be USB3 if there are no USB2 ports Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20220511220450.85367-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
57f23cd0bf
commit
873f323618
@ -707,6 +707,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
|
|||||||
u16 test_mode, u16 wIndex, unsigned long *flags)
|
u16 test_mode, u16 wIndex, unsigned long *flags)
|
||||||
__must_hold(&xhci->lock)
|
__must_hold(&xhci->lock)
|
||||||
{
|
{
|
||||||
|
struct usb_hcd *usb3_hcd = xhci_get_usb3_hcd(xhci);
|
||||||
int i, retval;
|
int i, retval;
|
||||||
|
|
||||||
/* Disable all Device Slots */
|
/* Disable all Device Slots */
|
||||||
@ -727,7 +728,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
|
|||||||
xhci_dbg(xhci, "Disable all port (PP = 0)\n");
|
xhci_dbg(xhci, "Disable all port (PP = 0)\n");
|
||||||
/* Power off USB3 ports*/
|
/* Power off USB3 ports*/
|
||||||
for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
|
for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
|
||||||
xhci_set_port_power(xhci, xhci->shared_hcd, i, false, flags);
|
xhci_set_port_power(xhci, usb3_hcd, i, false, flags);
|
||||||
/* Power off USB2 ports*/
|
/* Power off USB2 ports*/
|
||||||
for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
|
for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
|
||||||
xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
|
xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
|
||||||
|
@ -1072,7 +1072,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
|
|||||||
struct usb_hcd *hcd;
|
struct usb_hcd *hcd;
|
||||||
|
|
||||||
if (udev->speed >= USB_SPEED_SUPER)
|
if (udev->speed >= USB_SPEED_SUPER)
|
||||||
hcd = xhci->shared_hcd;
|
hcd = xhci_get_usb3_hcd(xhci);
|
||||||
else
|
else
|
||||||
hcd = xhci->main_hcd;
|
hcd = xhci->main_hcd;
|
||||||
|
|
||||||
@ -2362,10 +2362,11 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
|
|||||||
xhci->usb2_rhub.num_ports = USB_MAXCHILDREN;
|
xhci->usb2_rhub.num_ports = USB_MAXCHILDREN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (!xhci->usb2_rhub.num_ports)
|
||||||
* Note we could have all USB 3.0 ports, or all USB 2.0 ports.
|
xhci_info(xhci, "USB2 root hub has no ports\n");
|
||||||
* Not sure how the USB core will handle a hub with no ports...
|
|
||||||
*/
|
if (!xhci->usb3_rhub.num_ports)
|
||||||
|
xhci_info(xhci, "USB3 root hub has no ports\n");
|
||||||
|
|
||||||
xhci_create_rhub_port_array(xhci, &xhci->usb2_rhub, flags);
|
xhci_create_rhub_port_array(xhci, &xhci->usb2_rhub, flags);
|
||||||
xhci_create_rhub_port_array(xhci, &xhci->usb3_rhub, flags);
|
xhci_create_rhub_port_array(xhci, &xhci->usb3_rhub, flags);
|
||||||
|
@ -486,6 +486,10 @@ static void compliance_mode_recovery(struct timer_list *t)
|
|||||||
|
|
||||||
xhci = from_timer(xhci, t, comp_mode_recovery_timer);
|
xhci = from_timer(xhci, t, comp_mode_recovery_timer);
|
||||||
rhub = &xhci->usb3_rhub;
|
rhub = &xhci->usb3_rhub;
|
||||||
|
hcd = rhub->hcd;
|
||||||
|
|
||||||
|
if (!hcd)
|
||||||
|
return;
|
||||||
|
|
||||||
for (i = 0; i < rhub->num_ports; i++) {
|
for (i = 0; i < rhub->num_ports; i++) {
|
||||||
temp = readl(rhub->ports[i]->addr);
|
temp = readl(rhub->ports[i]->addr);
|
||||||
@ -499,7 +503,6 @@ static void compliance_mode_recovery(struct timer_list *t)
|
|||||||
i + 1);
|
i + 1);
|
||||||
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
|
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
|
||||||
"Attempting compliance mode recovery");
|
"Attempting compliance mode recovery");
|
||||||
hcd = xhci->shared_hcd;
|
|
||||||
|
|
||||||
if (hcd->state == HC_STATE_SUSPENDED)
|
if (hcd->state == HC_STATE_SUSPENDED)
|
||||||
usb_hcd_resume_root_hub(hcd);
|
usb_hcd_resume_root_hub(hcd);
|
||||||
@ -612,14 +615,11 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
|
|||||||
xhci_halt(xhci);
|
xhci_halt(xhci);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
xhci->shared_hcd->state = HC_STATE_RUNNING;
|
|
||||||
xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
||||||
|
|
||||||
if (xhci->quirks & XHCI_NEC_HOST)
|
if (xhci->quirks & XHCI_NEC_HOST)
|
||||||
xhci_ring_cmd_db(xhci);
|
xhci_ring_cmd_db(xhci);
|
||||||
|
|
||||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
|
||||||
"Finished xhci_run for USB3 roothub");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +694,7 @@ int xhci_run(struct usb_hcd *hcd)
|
|||||||
xhci_free_command(xhci, command);
|
xhci_free_command(xhci, command);
|
||||||
}
|
}
|
||||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||||
"Finished xhci_run for USB2 roothub");
|
"Finished %s for main hcd", __func__);
|
||||||
|
|
||||||
set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags);
|
set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags);
|
||||||
|
|
||||||
@ -702,6 +702,9 @@ int xhci_run(struct usb_hcd *hcd)
|
|||||||
|
|
||||||
xhci_debugfs_init(xhci);
|
xhci_debugfs_init(xhci);
|
||||||
|
|
||||||
|
if (xhci_has_one_roothub(xhci))
|
||||||
|
return xhci_run_finished(xhci);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xhci_run);
|
EXPORT_SYMBOL_GPL(xhci_run);
|
||||||
@ -994,7 +997,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (hcd->state != HC_STATE_SUSPENDED ||
|
if (hcd->state != HC_STATE_SUSPENDED ||
|
||||||
xhci->shared_hcd->state != HC_STATE_SUSPENDED)
|
(xhci->shared_hcd && xhci->shared_hcd->state != HC_STATE_SUSPENDED))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Clear root port wake on bits if wakeup not allowed. */
|
/* Clear root port wake on bits if wakeup not allowed. */
|
||||||
@ -1011,15 +1014,18 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
|||||||
__func__, hcd->self.busnum);
|
__func__, hcd->self.busnum);
|
||||||
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||||
del_timer_sync(&hcd->rh_timer);
|
del_timer_sync(&hcd->rh_timer);
|
||||||
clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
if (xhci->shared_hcd) {
|
||||||
del_timer_sync(&xhci->shared_hcd->rh_timer);
|
clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
||||||
|
del_timer_sync(&xhci->shared_hcd->rh_timer);
|
||||||
|
}
|
||||||
|
|
||||||
if (xhci->quirks & XHCI_SUSPEND_DELAY)
|
if (xhci->quirks & XHCI_SUSPEND_DELAY)
|
||||||
usleep_range(1000, 1500);
|
usleep_range(1000, 1500);
|
||||||
|
|
||||||
spin_lock_irq(&xhci->lock);
|
spin_lock_irq(&xhci->lock);
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
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 */
|
/* step 1: stop endpoint */
|
||||||
/* skipped assuming that port suspend has done */
|
/* skipped assuming that port suspend has done */
|
||||||
|
|
||||||
@ -1119,7 +1125,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
msleep(100);
|
msleep(100);
|
||||||
|
|
||||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
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);
|
spin_lock_irq(&xhci->lock);
|
||||||
|
|
||||||
@ -1179,7 +1186,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
|
|
||||||
/* Let the USB core know _both_ roothubs lost power. */
|
/* 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->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_dbg(xhci, "Stop HCD\n");
|
||||||
xhci_halt(xhci);
|
xhci_halt(xhci);
|
||||||
@ -1219,12 +1227,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
|
|
||||||
xhci_dbg(xhci, "Start the primary HCD\n");
|
xhci_dbg(xhci, "Start the primary HCD\n");
|
||||||
retval = xhci_run(hcd->primary_hcd);
|
retval = xhci_run(hcd->primary_hcd);
|
||||||
if (!retval) {
|
if (!retval && secondary_hcd) {
|
||||||
xhci_dbg(xhci, "Start the secondary HCD\n");
|
xhci_dbg(xhci, "Start the secondary HCD\n");
|
||||||
retval = xhci_run(secondary_hcd);
|
retval = xhci_run(secondary_hcd);
|
||||||
}
|
}
|
||||||
hcd->state = HC_STATE_SUSPENDED;
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1262,7 +1271,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pending_portevent) {
|
if (pending_portevent) {
|
||||||
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);
|
usb_hcd_resume_root_hub(hcd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1281,8 +1291,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
/* Re-enable port polling. */
|
/* Re-enable port polling. */
|
||||||
xhci_dbg(xhci, "%s: starting usb%d port polling.\n",
|
xhci_dbg(xhci, "%s: starting usb%d port polling.\n",
|
||||||
__func__, hcd->self.busnum);
|
__func__, hcd->self.busnum);
|
||||||
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
if (xhci->shared_hcd) {
|
||||||
usb_hcd_poll_rh_status(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);
|
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||||
usb_hcd_poll_rh_status(hcd);
|
usb_hcd_poll_rh_status(hcd);
|
||||||
|
|
||||||
@ -5281,9 +5293,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||||||
|
|
||||||
xhci = hcd_to_xhci(hcd);
|
xhci = hcd_to_xhci(hcd);
|
||||||
|
|
||||||
if (usb_hcd_is_primary_hcd(hcd)) {
|
if (!usb_hcd_is_primary_hcd(hcd)) {
|
||||||
xhci_hcd_init_usb2_data(xhci, hcd);
|
|
||||||
} else {
|
|
||||||
xhci_hcd_init_usb3_data(xhci, hcd);
|
xhci_hcd_init_usb3_data(xhci, hcd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5364,6 +5374,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||||||
return retval;
|
return retval;
|
||||||
xhci_dbg(xhci, "Called HCD init\n");
|
xhci_dbg(xhci, "Called HCD init\n");
|
||||||
|
|
||||||
|
if (xhci_hcd_is_usb3(hcd))
|
||||||
|
xhci_hcd_init_usb3_data(xhci, hcd);
|
||||||
|
else
|
||||||
|
xhci_hcd_init_usb2_data(xhci, hcd);
|
||||||
|
|
||||||
xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
|
xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
|
||||||
xhci->hcc_params, xhci->hci_version, xhci->quirks);
|
xhci->hcc_params, xhci->hci_version, xhci->quirks);
|
||||||
|
|
||||||
|
@ -1911,6 +1911,8 @@ struct xhci_hcd {
|
|||||||
unsigned hw_lpm_support:1;
|
unsigned hw_lpm_support:1;
|
||||||
/* Broken Suspend flag for SNPS Suspend resume issue */
|
/* Broken Suspend flag for SNPS Suspend resume issue */
|
||||||
unsigned broken_suspend:1;
|
unsigned broken_suspend:1;
|
||||||
|
/* Indicates that omitting hcd is supported if root hub has no ports */
|
||||||
|
unsigned allow_single_roothub:1;
|
||||||
/* cached usb2 extened protocol capabilites */
|
/* cached usb2 extened protocol capabilites */
|
||||||
u32 *ext_caps;
|
u32 *ext_caps;
|
||||||
unsigned int num_ext_caps;
|
unsigned int num_ext_caps;
|
||||||
@ -1966,6 +1968,30 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
|
|||||||
return xhci->main_hcd;
|
return xhci->main_hcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct usb_hcd *xhci_get_usb3_hcd(struct xhci_hcd *xhci)
|
||||||
|
{
|
||||||
|
if (xhci->shared_hcd)
|
||||||
|
return xhci->shared_hcd;
|
||||||
|
|
||||||
|
if (!xhci->usb2_rhub.num_ports)
|
||||||
|
return xhci->main_hcd;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool xhci_hcd_is_usb3(struct usb_hcd *hcd)
|
||||||
|
{
|
||||||
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
|
|
||||||
|
return hcd == xhci_get_usb3_hcd(xhci);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci)
|
||||||
|
{
|
||||||
|
return xhci->allow_single_roothub &&
|
||||||
|
(!xhci->usb2_rhub.num_ports || !xhci->usb3_rhub.num_ports);
|
||||||
|
}
|
||||||
|
|
||||||
#define xhci_dbg(xhci, fmt, args...) \
|
#define xhci_dbg(xhci, fmt, args...) \
|
||||||
dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
|
dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
|
||||||
#define xhci_err(xhci, fmt, args...) \
|
#define xhci_err(xhci, fmt, args...) \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user