CHROMIUM: usb: dwc3: rockchip: avoid removing hcd while system is frozen
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc3 / dwc3-rockchip.c
index 19b53f644be85c896528f74ddfe420e2b9e66714..1bb95df6e7d6dd9f25bbb0bcedb52d5a2d40f065 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 #include <linux/extcon.h>
+#include <linux/freezer.h>
 #include <linux/reset.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -240,6 +241,26 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
                                        msleep(100);
                                }
 
+#ifdef CONFIG_FREEZER
+                               /*
+                                * usb_remove_hcd() may call usb_disconnect() to
+                                * remove a block device pluged in before.
+                                * Unfortunately, the block layer suspend/resume
+                                * path is fundamentally broken due to freezable
+                                * kthreads and workqueue and may deadlock if a
+                                * block device gets removed while resume is in
+                                * progress.
+                                *
+                                * We need to add a ugly hack to avoid removing
+                                * hcd and kicking off device removal while
+                                * freezer is active. This is a joke but does
+                                * avoid this particular deadlock when test with
+                                * USB-C HUB and USB2/3 flash drive.
+                                */
+                               while (pm_freezing)
+                                       usleep_range(10000, 11000);
+#endif
+
                                usb_remove_hcd(hcd->shared_hcd);
                                usb_remove_hcd(hcd);
                        }