Skip to content

Commit d58fc9e

Browse files
kishongregkh
authored andcommitted
usb: core: hcd: Add support for deferring roothub registration
commit 58877b0 upstream. 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 996f7c4 commit d58fc9e

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
@@ -2640,6 +2640,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
26402640
{
26412641
int retval;
26422642
struct usb_device *rhdev;
2643+
struct usb_hcd *shared_hcd;
26432644

26442645
if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
26452646
hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
@@ -2796,13 +2797,26 @@ int usb_add_hcd(struct usb_hcd *hcd,
27962797
goto err_hcd_driver_start;
27972798
}
27982799

2800+
/* starting here, usbcore will pay attention to the shared HCD roothub */
2801+
shared_hcd = hcd->shared_hcd;
2802+
if (!usb_hcd_is_primary_hcd(hcd) && shared_hcd && HCD_DEFER_RH_REGISTER(shared_hcd)) {
2803+
retval = register_root_hub(shared_hcd);
2804+
if (retval != 0)
2805+
goto err_register_root_hub;
2806+
2807+
if (shared_hcd->uses_new_polling && HCD_POLL_RH(shared_hcd))
2808+
usb_hcd_poll_rh_status(shared_hcd);
2809+
}
2810+
27992811
/* starting here, usbcore will pay attention to this root hub */
2800-
retval = register_root_hub(hcd);
2801-
if (retval != 0)
2802-
goto err_register_root_hub;
2812+
if (!HCD_DEFER_RH_REGISTER(hcd)) {
2813+
retval = register_root_hub(hcd);
2814+
if (retval != 0)
2815+
goto err_register_root_hub;
28032816

2804-
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
2805-
usb_hcd_poll_rh_status(hcd);
2817+
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
2818+
usb_hcd_poll_rh_status(hcd);
2819+
}
28062820

28072821
return retval;
28082822

@@ -2845,6 +2859,7 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
28452859
void usb_remove_hcd(struct usb_hcd *hcd)
28462860
{
28472861
struct usb_device *rhdev = hcd->self.root_hub;
2862+
bool rh_registered;
28482863

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

@@ -2855,6 +2870,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
28552870

28562871
dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
28572872
spin_lock_irq (&hcd_root_hub_lock);
2873+
rh_registered = hcd->rh_registered;
28582874
hcd->rh_registered = 0;
28592875
spin_unlock_irq (&hcd_root_hub_lock);
28602876

@@ -2864,7 +2880,8 @@ void usb_remove_hcd(struct usb_hcd *hcd)
28642880
cancel_work_sync(&hcd->died_work);
28652881

28662882
mutex_lock(&usb_bus_idr_lock);
2867-
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
2883+
if (rh_registered)
2884+
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
28682885
mutex_unlock(&usb_bus_idr_lock);
28692886

28702887
/*

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)