Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751366AbdH1Qfm (ORCPT ); Mon, 28 Aug 2017 12:35:42 -0400 Received: from mga04.intel.com ([192.55.52.120]:64028 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751192AbdH1Qfk (ORCPT ); Mon, 28 Aug 2017 12:35:40 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.41,442,1498546800"; d="scan'208";a="142811987" From: anshuman.gupta@intel.com To: stern@rowland.harvard.edu, mathias.nyman@intel.com, linux-usb@vger.kernel.org Cc: linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, anshuman.gupta@intel.com Subject: [PATCH v2] USB: xhci: reducing HS port auto-resume latency. Date: Mon, 28 Aug 2017 22:04:41 +0530 Message-Id: <1503938081-17387-1-git-send-email-anshuman.gupta@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <599DA6A1.8070801@intel.com> References: <599DA6A1.8070801@intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3615 Lines: 88 From: Anshuman Gupta This patch will improve the variable auto-resume latency of an usb-port. When xhci gets a HS port status change event interrupt due to PORT_PLC (port link state transition), linux Host controller driver drives the resume signalling on the bus for the amount of time defined by USB_RESUME_TIMEOUT(40ms) macro. This 40ms delay for resume signalling is in acceptable limit, but it get worse when xhci goes for polling mode in order to detect other events on its ports and modify rh_timer timer with a variable time out of 1ms to (HZ/4)ms. drivers/usb/core/hcd.c line 799 mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)). Due to above variable timeout usb auto-resume latency varies from 40ms to ~300ms(when HZ=1000). Log Snippet: ~128ms latency [ 53.112049] hub 1-0:1.0: state 7 ports 12 chg 0000 evt 0000 [ 53.229200] hub 1-0:1.0: state 7 ports 12 chg 0000 evt 0004 [ 53.240177] usb 1-2: usb wakeup-resume [ 53.240195] usb 1-2: finish resume [ 53.240357] usb usb1-port2: resume, status 0 ----------------------------------------------------------------- ~300ms latency [ 59.946620] hub 1-0:1.0: state 7 ports 12 chg 0000 evt 0000 [ 59.979341] hub 1-0:1.0: state 7 ports 12 chg 0000 evt 0000 [ 60.229342] hub 1-0:1.0: state 7 ports 12 chg 0000 evt 0004 [ 60.251321] usb 1-2: usb wakeup-resume [ 60.251335] usb 1-2: finish resume [ 60.251539] usb usb1-port2: resume, status 0 xhci bug behind the higher latency: When HS port is resuming, xhci passes the resume event to hub event thread after USB_RESUME_TIMEOUT delay. it modify rh_timer with USB_RESUME_TIMEOUT delay, and set the polling mode flag and invoke usb_hcd_poll_rh_status() function manually. This eventually makes hub event thread to read the HS port status before it resumes, since polling mode flag is set, host controller driver modify rh_timer again with (HZ/4)ms delay, This makes hub event thread to wait for (HZ/4)ms. which causes higher auto-resume latency. This variable resume latency can be optimized, as in case of HS port resume event rh_timer has already been modified with USB_RESUME_TIMEOUT (40ms) delay, leaving the rest to GetPortStatus. We can avoid calling usb_hcd_poll_rh_status() function manually in case of HS port resume event. This patch set the HCD_FLAG_POLL_RH to hcd->flags after modification of rh_timer, and avoid calling usb_hcd_poll_rh_status(), This makes to call usb_hcd_poll_rh_status() by rh_timer and passing the HS port resume event to hub event thread after USB_RESUME_TIMEOUT delay. Signed-off-by: Anshuman Gupta --- Changes in v2 - Make the commit message more clearer. - Changing the comment. drivers/usb/host/xhci-ring.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cc368ad..0bccff1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1677,9 +1677,14 @@ static void handle_port_status(struct xhci_hcd *xhci, bus_state->resume_done[faked_port_index] = jiffies + msecs_to_jiffies(USB_RESUME_TIMEOUT); set_bit(faked_port_index, &bus_state->resuming_ports); + /* Do the rest in GetPortStatus after resume time delay. + * Avoid calling usb_hcd_poll_rh_status before that,so + * an usb port can auto-resume after resume time delay. + */ + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); mod_timer(&hcd->rh_timer, bus_state->resume_done[faked_port_index]); - /* Do the rest in GetPortStatus */ + bogus_port_status = true; } } -- 2.7.4