Skip to content

Commit 58877b0

Browse files
kishongregkh
authored andcommitted
usb: core: hcd: Add support for deferring roothub registration
It has been observed with certain PCIe USB cards (like Inateck connected to AM64 EVM or J7200 EVM) that as soon as the primary roothub is registered, port status change is handled even before xHC is running leading to cold plug USB devices not detected. For such cases, registering both the root hubs along with the second HCD is required. Add support for deferring roothub registration in usb_add_hcd(), so that both primary and secondary roothubs are registered along with the second HCD. CC: stable@vger.kernel.org # 5.4+ Suggested-by: Mathias Nyman <mathias.nyman@linux.intel.com> Tested-by: Chris Chiu <chris.chiu@canonical.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> Link: https://lore.kernel.org/r/20210909064200.16216-2-kishon@ti.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 91bb163 commit 58877b0

File tree

2 files changed

+25
-6
lines changed

2 files changed

+25
-6
lines changed

drivers/usb/core/hcd.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,6 +2775,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
27752775
{
27762776
int retval;
27772777
struct usb_device *rhdev;
2778+
struct usb_hcd *shared_hcd;
27782779

27792780
if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
27802781
hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
@@ -2935,13 +2936,26 @@ int usb_add_hcd(struct usb_hcd *hcd,
29352936
goto err_hcd_driver_start;
29362937
}
29372938

2939+
/* starting here, usbcore will pay attention to the shared HCD roothub */
2940+
shared_hcd = hcd->shared_hcd;
2941+
if (!usb_hcd_is_primary_hcd(hcd) && shared_hcd && HCD_DEFER_RH_REGISTER(shared_hcd)) {
2942+
retval = register_root_hub(shared_hcd);
2943+
if (retval != 0)
2944+
goto err_register_root_hub;
2945+
2946+
if (shared_hcd->uses_new_polling && HCD_POLL_RH(shared_hcd))
2947+
usb_hcd_poll_rh_status(shared_hcd);
2948+
}
2949+
29382950
/* starting here, usbcore will pay attention to this root hub */
2939-
retval = register_root_hub(hcd);
2940-
if (retval != 0)
2941-
goto err_register_root_hub;
2951+
if (!HCD_DEFER_RH_REGISTER(hcd)) {
2952+
retval = register_root_hub(hcd);
2953+
if (retval != 0)
2954+
goto err_register_root_hub;
29422955

2943-
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
2944-
usb_hcd_poll_rh_status(hcd);
2956+
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
2957+
usb_hcd_poll_rh_status(hcd);
2958+
}
29452959

29462960
return retval;
29472961

@@ -2985,6 +2999,7 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
29852999
void usb_remove_hcd(struct usb_hcd *hcd)
29863000
{
29873001
struct usb_device *rhdev = hcd->self.root_hub;
3002+
bool rh_registered;
29883003

29893004
dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
29903005

@@ -2995,6 +3010,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
29953010

29963011
dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
29973012
spin_lock_irq (&hcd_root_hub_lock);
3013+
rh_registered = hcd->rh_registered;
29983014
hcd->rh_registered = 0;
29993015
spin_unlock_irq (&hcd_root_hub_lock);
30003016

@@ -3004,7 +3020,8 @@ void usb_remove_hcd(struct usb_hcd *hcd)
30043020
cancel_work_sync(&hcd->died_work);
30053021

30063022
mutex_lock(&usb_bus_idr_lock);
3007-
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
3023+
if (rh_registered)
3024+
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
30083025
mutex_unlock(&usb_bus_idr_lock);
30093026

30103027
/*

include/linux/usb/hcd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct usb_hcd {
124124
#define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */
125125
#define HCD_FLAG_DEAD 6 /* controller has died? */
126126
#define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */
127+
#define HCD_FLAG_DEFER_RH_REGISTER 8 /* Defer roothub registration */
127128

128129
/* The flags can be tested using these macros; they are likely to
129130
* be slightly faster than test_bit().
@@ -134,6 +135,7 @@ struct usb_hcd {
134135
#define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
135136
#define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
136137
#define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))
138+
#define HCD_DEFER_RH_REGISTER(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEFER_RH_REGISTER))
137139

138140
/*
139141
* Specifies if interfaces are authorized by default

0 commit comments

Comments
 (0)