Re: [Query] checking hub port status while USB 2.0 port is resuming.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 28 May 2018, Anshuman Gupta wrote:

> > It sounds like you want the code in usb_port_resume() to check and see
> > whether the port has already received a wakeup signal and hasn't
> > finished processing it yet.
>   yes.
> > 
> > There's no way to do this for ports on external hubs, but in principle 
> > it can be done for ports on root hubs.  If we see that a wakeup signal 
> > was received, we can call pm_wakeup_event().  Will that be good enough?
>   Yeah, i think this will be enough for us. 

Okay, here's a patch which should do want you want.  I have not tested 
it; let me know if it's okay.

(I'm not entirely certain about the xhci-hcd portions.  If necessary we 
can get help from the driver's maintainer.)

Alan Stern



Index: usb-4.x/drivers/usb/core/hub.c
===================================================================
--- usb-4.x.orig/drivers/usb/core/hub.c
+++ usb-4.x/drivers/usb/core/hub.c
@@ -3636,11 +3636,52 @@ static int hub_suspend(struct usb_interf
 	return 0;
 }
 
+/* Report wakeup requests from the ports of a resuming root hub */
+static void report_wakeup_requests(struct usb_hub *hub)
+{
+	struct usb_device	*hdev = hub->hdev;
+	struct usb_hcd		*hcd;
+	unsigned long		resuming_ports;
+	int			i;
+
+	if (hdev->parent)
+		return;		/* Not a root hub */
+
+	hcd = bus_to_hcd(hdev->bus);
+	if (hcd->driver->get_resuming_ports) {
+
+		/*
+		 * The get_resuming_ports() method returns a bitmap (origin 0)
+		 * of ports which have started wakeup signaling but have not
+		 * yet finished resuming.  During system resume we will
+		 * resume all the enabled ports, regardless of any wakeup
+		 * signals, which means the wakeup requests would be lost.
+		 * To prevent this, report them to the PM core here.
+		 */
+		resuming_ports = hcd->driver->get_resuming_ports(hcd);
+		for (i = 0; i < hdev->maxchild; ++i) {
+			if (test_bit(i, &resuming_ports)) {
+				struct usb_port *port_dev = hub->ports[i];
+
+				pm_wakeup_event(&port_dev->dev, 0);
+			}
+		}
+	}
+}
+
 static int hub_resume(struct usb_interface *intf)
 {
 	struct usb_hub *hub = usb_get_intfdata(intf);
 
 	dev_dbg(&intf->dev, "%s\n", __func__);
+
+	/*
+	 * This should be called only for system resume, not runtime resume.
+	 * We can't tell the difference here, so some wakeup requests will be
+	 * reported more than once.  This shouldn't matter much.
+	 */
+	report_wakeup_requests(hub);
+
 	hub_activate(hub, HUB_RESUME);
 	return 0;
 }
Index: usb-4.x/include/linux/usb/hcd.h
===================================================================
--- usb-4.x.orig/include/linux/usb/hcd.h
+++ usb-4.x/include/linux/usb/hcd.h
@@ -322,6 +322,7 @@ struct hc_driver {
 	int	(*bus_suspend)(struct usb_hcd *);
 	int	(*bus_resume)(struct usb_hcd *);
 	int	(*start_port_reset)(struct usb_hcd *, unsigned port_num);
+	unsigned long	(*get_resuming_ports)(struct usb_hcd *);
 
 		/* force handover of high-speed port to full-speed companion */
 	void	(*relinquish_port)(struct usb_hcd *, int);
Index: usb-4.x/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-4.x.orig/drivers/usb/host/ehci-hcd.c
+++ usb-4.x/drivers/usb/host/ehci-hcd.c
@@ -1226,6 +1226,7 @@ static const struct hc_driver ehci_hc_dr
 	.bus_resume =		ehci_bus_resume,
 	.relinquish_port =	ehci_relinquish_port,
 	.port_handed_over =	ehci_port_handed_over,
+	.get_resuming_ports =	ehci_get_resuming_ports,
 
 	/*
 	 * device support
Index: usb-4.x/drivers/usb/host/ehci-hub.c
===================================================================
--- usb-4.x.orig/drivers/usb/host/ehci-hub.c
+++ usb-4.x/drivers/usb/host/ehci-hub.c
@@ -512,10 +512,18 @@ static int ehci_bus_resume (struct usb_h
 	return -ESHUTDOWN;
 }
 
+static unsigned long ehci_get_resuming_ports(struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+
+	return ehci->resuming_ports;
+}
+
 #else
 
 #define ehci_bus_suspend	NULL
 #define ehci_bus_resume		NULL
+#define ehci_get_resuming_ports	NULL
 
 #endif	/* CONFIG_PM */
 
Index: usb-4.x/drivers/usb/host/xhci-hub.c
===================================================================
--- usb-4.x.orig/drivers/usb/host/xhci-hub.c
+++ usb-4.x/drivers/usb/host/xhci-hub.c
@@ -1684,4 +1684,15 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 	return 0;
 }
 
+unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd)
+{
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+	struct xhci_bus_state *bus_state;
+
+	bus_state = &xhci->bus_state[hcd_index(hcd)];
+
+	/* USB3 port wakeups are reported via usb_wakeup_notification() */
+	return bus_state->resuming_ports;	/* USB2 ports only */
+}
+
 #endif	/* CONFIG_PM */
Index: usb-4.x/drivers/usb/host/xhci.c
===================================================================
--- usb-4.x.orig/drivers/usb/host/xhci.c
+++ usb-4.x/drivers/usb/host/xhci.c
@@ -5019,6 +5019,7 @@ static const struct hc_driver xhci_hc_dr
 	.hub_status_data =	xhci_hub_status_data,
 	.bus_suspend =		xhci_bus_suspend,
 	.bus_resume =		xhci_bus_resume,
+	.get_resuming_ports =	xhci_get_resuming_ports,
 
 	/*
 	 * call back when device connected and addressed
Index: usb-4.x/drivers/usb/host/xhci.h
===================================================================
--- usb-4.x.orig/drivers/usb/host/xhci.h
+++ usb-4.x/drivers/usb/host/xhci.h
@@ -2104,9 +2104,11 @@ void xhci_hc_died(struct xhci_hcd *xhci)
 #ifdef CONFIG_PM
 int xhci_bus_suspend(struct usb_hcd *hcd);
 int xhci_bus_resume(struct usb_hcd *hcd);
+unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd);
 #else
 #define	xhci_bus_suspend	NULL
 #define	xhci_bus_resume		NULL
+#define	xhci_get_resuming_ports	NULL
 #endif	/* CONFIG_PM */
 
 u32 xhci_port_state_to_neutral(u32 state);

--
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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux