linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mathias Nyman <mathias.nyman@linux.intel.com>
To: Kai-Heng Feng <kai.heng.feng@canonical.com>,
	mathias.nyman@intel.com, gregkh@linuxfoundation.org,
	stern@rowland.harvard.edu
Cc: acelan.kao@canonical.com, linux-usb@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [RESEND] [PATCH v2 2/3] xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0
Date: Mon, 10 Feb 2020 16:31:15 +0200	[thread overview]
Message-ID: <d65a1730-e725-ba1b-9272-0021346697e8@linux.intel.com> (raw)
In-Reply-To: <20200205112633.25995-2-kai.heng.feng@canonical.com>

On 5.2.2020 13.26, Kai-Heng Feng wrote:
> Like U3 case, xHCI spec doesn't specify the upper bound of U0 transition
> time. The 20ms is not enough for some devices.
> 
> Intead of polling PLS or PLC, we can facilitate the port change event to
> know that the link transits to U0 is completed.
> 
> While at it, also separate U0 and U3 case to make the code cleaner.
> 
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v2:
>  - Seperate U0 and U3 case.
>  - Prevent setting U0 from non-U state.
>  - Move the completion from per port to bus_state.
> 
>  drivers/usb/host/xhci-hub.c  | 43 +++++++++++++++++++++++++-----------
>  drivers/usb/host/xhci-mem.c  |  2 ++
>  drivers/usb/host/xhci-ring.c |  1 +
>  drivers/usb/host/xhci.h      |  1 +
>  4 files changed, 34 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index d3c5bcf76755..0a5d8b28b99f 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -1297,7 +1297,32 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
>  					 wIndex, link_state);
>  				goto error;
>  			}
> +
> +			if (link_state == USB_SS_PORT_LS_U0) {
> +				if ((temp & PORT_PLS_MASK) == XDEV_U0)
> +					break;
> +
> +				if (!((temp & PORT_PLS_MASK) == XDEV_U1 ||
> +				    (temp & PORT_PLS_MASK) == XDEV_U2 ||
> +				    (temp & PORT_PLS_MASK) == XDEV_U3)) {
> +					xhci_warn(xhci, "Can only set port %d to U0 from U state\n",
> +							wIndex);

Port link state could be XDEV_RESUME or maybe even XDEV_RECOVERY if we race with a device
initiated resume.
I'll need to check how we should handle those. 

> +					goto error;
> +				}
> +				reinit_completion(&bus_state->link_change_done[wIndex]);
> +				xhci_set_link_state(xhci, ports[wIndex], USB_SS_PORT_LS_U0);
> +				spin_unlock_irqrestore(&xhci->lock, flags);
> +				if (!wait_for_completion_timeout(&bus_state->link_change_done[wIndex],
> +								 msecs_to_jiffies(100)))

Minor nit: rename link_change_done[] to u3exit_done[] 
see xhci 4.19.1.2.13.2 "U3", and the Host Initiated resume substate transition

> +					xhci_dbg(xhci, "missing U0 port change event for port %d\n",
> +						 wIndex);
> +				spin_lock_irqsave(&xhci->lock, flags);
> +				temp = readl(ports[wIndex]->addr);
> +				break;
> +			}
> +
>  			if (link_state == USB_SS_PORT_LS_U3) {
> +				int retries = 10;
>  				slot_id = xhci_find_slot_id_by_port(hcd, xhci,
>  						wIndex + 1);
>  				if (slot_id) {
> @@ -1308,26 +1333,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
>  					xhci_stop_device(xhci, slot_id, 1);
>  					spin_lock_irqsave(&xhci->lock, flags);
>  				}
> -			}
> -
> -			xhci_set_link_state(xhci, ports[wIndex], link_state);
> -
> -			spin_unlock_irqrestore(&xhci->lock, flags);
> -			if (link_state == USB_SS_PORT_LS_U3) {
> -				int retries = 10;
> -
> +				xhci_set_link_state(xhci, ports[wIndex], USB_SS_PORT_LS_U3);
> +				spin_unlock_irqrestore(&xhci->lock, flags);
>  				while (retries--) {
>  					msleep(10); /* wait device to enter */
>  					temp = readl(ports[wIndex]->addr);
>  					if ((temp & PORT_PLS_MASK) == XDEV_U3)
>  						break;
>  				}
> -			}
> -			spin_lock_irqsave(&xhci->lock, flags);
> -
> -			temp = readl(ports[wIndex]->addr);
> -			if (link_state == USB_SS_PORT_LS_U3)
> +				spin_lock_irqsave(&xhci->lock, flags);
> +				temp = readl(ports[wIndex]->addr);
>  				bus_state->suspended_ports |= 1 << wIndex;
> +			}
>  			break;
>  		case USB_PORT_FEAT_POWER:
>  			/*
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index 3b1388fa2f36..aceb8c1af775 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -2531,6 +2531,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
>  		xhci->usb3_rhub.bus_state.resume_done[i] = 0;
>  		/* Only the USB 2.0 completions will ever be used. */
>  		init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]);
> +		init_completion(&xhci->usb2_rhub.bus_state.link_change_done[i]);

Not needed for usb2, it doesn't support Set Port Feature PORT_LINK_STATE requests

> +		init_completion(&xhci->usb3_rhub.bus_state.link_change_done[i]);

rename to u3exit_done

>  	}
>  
>  	if (scratchpad_alloc(xhci, flags))
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index d23f7408c81f..4d0f8dab069a 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -1677,6 +1677,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
>  	     (portsc & PORT_PLS_MASK) == XDEV_U1 ||
>  	     (portsc & PORT_PLS_MASK) == XDEV_U2)) {
>  		xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
> +		complete(&bus_state->link_change_done[hcd_portnum]);
>  		/* We've just brought the device into U0/1/2 through either the
>  		 * Resume state after a device remote wakeup, or through the
>  		 * U3Exit state after a host-initiated resume.  If it's a device
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 13d8838cd552..b5d443ce0750 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1694,6 +1694,7 @@ struct xhci_bus_state {
>  	/* Which ports are waiting on RExit to U0 transition. */
>  	unsigned long		rexit_ports;
>  	struct completion	rexit_done[USB_MAXCHILDREN];
> +	struct completion	link_change_done[USB_MAXCHILDREN];
>  };
>  
>  

I can do these minor changes and try out these first two patches.
No need to resend.

The last 3/3 patch isn't really tied to the first two, or even xhci, 
and should probably go as a separate patch.

-Mathias

  reply	other threads:[~2020-02-10 14:29 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-05 11:26 [RESEND] [PATCH v2 1/3] xhci: Ensure link state is U3 after setting USB_SS_PORT_LS_U3 Kai-Heng Feng
2020-02-05 11:26 ` [RESEND] [PATCH v2 2/3] xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0 Kai-Heng Feng
2020-02-10 14:31   ` Mathias Nyman [this message]
2020-02-05 11:26 ` [RESEND] [PATCH v2 3/3] USB: Disable LPM on WD19's Realtek Hub Kai-Heng Feng
2020-03-11  3:32   ` Kai-Heng Feng
2020-03-11 14:15     ` Alan Stern

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d65a1730-e725-ba1b-9272-0021346697e8@linux.intel.com \
    --to=mathias.nyman@linux.intel.com \
    --cc=acelan.kao@canonical.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=kai.heng.feng@canonical.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).