usb: hub: Fix link power management max exit latency (MEL) calculations
commit 1bf2761c837571a66ec290fb66c90413821ffda2 upstream. Maximum Exit Latency (MEL) value is used by host to know how much in advance it needs to start waking up a U1/U2 suspended link in order to service a periodic transfer in time. Current MEL calculation only includes the time to wake up the path from U1/U2 to U0. This is called tMEL1 in USB 3.1 section C 1.5.2 Total MEL = tMEL1 + tMEL2 +tMEL3 + tMEL4 which should additinally include: - tMEL2 which is the time it takes for PING message to reach device - tMEL3 time for device to process the PING and submit a PING_RESPONSE - tMEL4 time for PING_RESPONSE to traverse back upstream to host. Add the missing tMEL2, tMEL3 and tMEL4 to MEL calculation. Cc: <stable@kernel.org> # v3.5 Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20210715150122.1995966-1-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
8f087b4cf1
commit
e6343aab3e
|
@ -47,6 +47,7 @@
|
|||
|
||||
#define USB_TP_TRANSMISSION_DELAY 40 /* ns */
|
||||
#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */
|
||||
#define USB_PING_RESPONSE_TIME 400 /* ns */
|
||||
|
||||
/* Protect struct usb_device->state and ->children members
|
||||
* Note: Both are also protected by ->dev.sem, except that ->state can
|
||||
|
@ -181,8 +182,9 @@ int usb_device_supports_lpm(struct usb_device *udev)
|
|||
}
|
||||
|
||||
/*
|
||||
* Set the Maximum Exit Latency (MEL) for the host to initiate a transition from
|
||||
* either U1 or U2.
|
||||
* Set the Maximum Exit Latency (MEL) for the host to wakup up the path from
|
||||
* U1/U2, send a PING to the device and receive a PING_RESPONSE.
|
||||
* See USB 3.1 section C.1.5.2
|
||||
*/
|
||||
static void usb_set_lpm_mel(struct usb_device *udev,
|
||||
struct usb3_lpm_parameters *udev_lpm_params,
|
||||
|
@ -192,35 +194,37 @@ static void usb_set_lpm_mel(struct usb_device *udev,
|
|||
unsigned int hub_exit_latency)
|
||||
{
|
||||
unsigned int total_mel;
|
||||
unsigned int device_mel;
|
||||
unsigned int hub_mel;
|
||||
|
||||
/*
|
||||
* Calculate the time it takes to transition all links from the roothub
|
||||
* to the parent hub into U0. The parent hub must then decode the
|
||||
* packet (hub header decode latency) to figure out which port it was
|
||||
* bound for.
|
||||
*
|
||||
* The Hub Header decode latency is expressed in 0.1us intervals (0x1
|
||||
* means 0.1us). Multiply that by 100 to get nanoseconds.
|
||||
* tMEL1. time to transition path from host to device into U0.
|
||||
* MEL for parent already contains the delay up to parent, so only add
|
||||
* the exit latency for the last link (pick the slower exit latency),
|
||||
* and the hub header decode latency. See USB 3.1 section C 2.2.1
|
||||
* Store MEL in nanoseconds
|
||||
*/
|
||||
total_mel = hub_lpm_params->mel +
|
||||
(hub->descriptor->u.ss.bHubHdrDecLat * 100);
|
||||
max(udev_exit_latency, hub_exit_latency) * 1000 +
|
||||
hub->descriptor->u.ss.bHubHdrDecLat * 100;
|
||||
|
||||
/*
|
||||
* How long will it take to transition the downstream hub's port into
|
||||
* U0? The greater of either the hub exit latency or the device exit
|
||||
* latency.
|
||||
*
|
||||
* The BOS U1/U2 exit latencies are expressed in 1us intervals.
|
||||
* Multiply that by 1000 to get nanoseconds.
|
||||
* tMEL2. Time to submit PING packet. Sum of tTPTransmissionDelay for
|
||||
* each link + wHubDelay for each hub. Add only for last link.
|
||||
* tMEL4, the time for PING_RESPONSE to traverse upstream is similar.
|
||||
* Multiply by 2 to include it as well.
|
||||
*/
|
||||
device_mel = udev_exit_latency * 1000;
|
||||
hub_mel = hub_exit_latency * 1000;
|
||||
if (device_mel > hub_mel)
|
||||
total_mel += device_mel;
|
||||
else
|
||||
total_mel += hub_mel;
|
||||
total_mel += (__le16_to_cpu(hub->descriptor->u.ss.wHubDelay) +
|
||||
USB_TP_TRANSMISSION_DELAY) * 2;
|
||||
|
||||
/*
|
||||
* tMEL3, tPingResponse. Time taken by device to generate PING_RESPONSE
|
||||
* after receiving PING. Also add 2100ns as stated in USB 3.1 C 1.5.2.4
|
||||
* to cover the delay if the PING_RESPONSE is queued behind a Max Packet
|
||||
* Size DP.
|
||||
* Note these delays should be added only once for the entire path, so
|
||||
* add them to the MEL of the device connected to the roothub.
|
||||
*/
|
||||
if (!hub->hdev->parent)
|
||||
total_mel += USB_PING_RESPONSE_TIME + 2100;
|
||||
|
||||
udev_lpm_params->mel = total_mel;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user