From patchwork Wed May 30 20:50:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Stern X-Patchwork-Id: 10439851 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 13331601E9 for ; Wed, 30 May 2018 20:50:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E28A5295C6 for ; Wed, 30 May 2018 20:50:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DDC0829587; Wed, 30 May 2018 20:50:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B545C295F1 for ; Wed, 30 May 2018 20:50:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932273AbeE3Uum (ORCPT ); Wed, 30 May 2018 16:50:42 -0400 Received: from iolanthe.rowland.org ([192.131.102.54]:37522 "HELO iolanthe.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S932247AbeE3Uul (ORCPT ); Wed, 30 May 2018 16:50:41 -0400 Received: (qmail 20775 invoked by uid 2102); 30 May 2018 16:50:40 -0400 Received: from localhost (sendmail-bs@127.0.0.1) by localhost with SMTP; 30 May 2018 16:50:40 -0400 Date: Wed, 30 May 2018 16:50:40 -0400 (EDT) From: Alan Stern X-X-Sender: stern@iolanthe.rowland.org To: Anshuman Gupta cc: linux-usb@vger.kernel.org, Subject: Re: [Query] checking hub port status while USB 2.0 port is resuming. In-Reply-To: <20180528051132.GA9012@anshuman.gupta@intel.com> Message-ID: MIME-Version: 1.0 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html 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);