mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
usb: core: Track SuperSpeed Plus GenXxY
Introduce ssp_rate field to usb_device structure to capture the connected SuperSpeed Plus signaling rate generation and lane count with the corresponding usb_ssp_rate enum. Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Link: https://lore.kernel.org/r/b7805d121e5ae4ad5ae144bd860b6ac04ee47436.1615432770.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
71ca43f30d
commit
0299809be4
@ -2721,6 +2721,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
|
||||
rhdev->rx_lanes = 1;
|
||||
rhdev->tx_lanes = 1;
|
||||
rhdev->ssp_rate = USB_SSP_GEN_UNKNOWN;
|
||||
|
||||
switch (hcd->speed) {
|
||||
case HCD_USB11:
|
||||
@ -2738,8 +2739,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
case HCD_USB32:
|
||||
rhdev->rx_lanes = 2;
|
||||
rhdev->tx_lanes = 2;
|
||||
fallthrough;
|
||||
rhdev->ssp_rate = USB_SSP_GEN_2x2;
|
||||
rhdev->speed = USB_SPEED_SUPER_PLUS;
|
||||
break;
|
||||
case HCD_USB31:
|
||||
rhdev->ssp_rate = USB_SSP_GEN_2x1;
|
||||
rhdev->speed = USB_SPEED_SUPER_PLUS;
|
||||
break;
|
||||
default:
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
@ -2668,6 +2669,81 @@ out_authorized:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_port_ssp_rate - Match the extended port status to SSP rate
|
||||
* @hdev: The hub device
|
||||
* @ext_portstatus: extended port status
|
||||
*
|
||||
* Match the extended port status speed id to the SuperSpeed Plus sublink speed
|
||||
* capability attributes. Base on the number of connected lanes and speed,
|
||||
* return the corresponding enum usb_ssp_rate.
|
||||
*/
|
||||
static enum usb_ssp_rate get_port_ssp_rate(struct usb_device *hdev,
|
||||
u32 ext_portstatus)
|
||||
{
|
||||
struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
|
||||
u32 attr;
|
||||
u8 speed_id;
|
||||
u8 ssac;
|
||||
u8 lanes;
|
||||
int i;
|
||||
|
||||
if (!ssp_cap)
|
||||
goto out;
|
||||
|
||||
speed_id = ext_portstatus & USB_EXT_PORT_STAT_RX_SPEED_ID;
|
||||
lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1;
|
||||
|
||||
ssac = le32_to_cpu(ssp_cap->bmAttributes) &
|
||||
USB_SSP_SUBLINK_SPEED_ATTRIBS;
|
||||
|
||||
for (i = 0; i <= ssac; i++) {
|
||||
u8 ssid;
|
||||
|
||||
attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
|
||||
ssid = FIELD_GET(USB_SSP_SUBLINK_SPEED_SSID, attr);
|
||||
if (speed_id == ssid) {
|
||||
u16 mantissa;
|
||||
u8 lse;
|
||||
u8 type;
|
||||
|
||||
/*
|
||||
* Note: currently asymmetric lane types are only
|
||||
* applicable for SSIC operate in SuperSpeed protocol
|
||||
*/
|
||||
type = FIELD_GET(USB_SSP_SUBLINK_SPEED_ST, attr);
|
||||
if (type == USB_SSP_SUBLINK_SPEED_ST_ASYM_RX ||
|
||||
type == USB_SSP_SUBLINK_SPEED_ST_ASYM_TX)
|
||||
goto out;
|
||||
|
||||
if (FIELD_GET(USB_SSP_SUBLINK_SPEED_LP, attr) !=
|
||||
USB_SSP_SUBLINK_SPEED_LP_SSP)
|
||||
goto out;
|
||||
|
||||
lse = FIELD_GET(USB_SSP_SUBLINK_SPEED_LSE, attr);
|
||||
mantissa = FIELD_GET(USB_SSP_SUBLINK_SPEED_LSM, attr);
|
||||
|
||||
/* Convert to Gbps */
|
||||
for (; lse < USB_SSP_SUBLINK_SPEED_LSE_GBPS; lse++)
|
||||
mantissa /= 1000;
|
||||
|
||||
if (mantissa >= 10 && lanes == 1)
|
||||
return USB_SSP_GEN_2x1;
|
||||
|
||||
if (mantissa >= 10 && lanes == 2)
|
||||
return USB_SSP_GEN_2x2;
|
||||
|
||||
if (mantissa >= 5 && lanes == 2)
|
||||
return USB_SSP_GEN_1x2;
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return USB_SSP_GEN_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if port speed is SuperSpeedPlus, 0 otherwise
|
||||
* check it from the link protocol field of the current speed ID attribute.
|
||||
@ -2850,9 +2926,11 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
||||
/* extended portstatus Rx and Tx lane count are zero based */
|
||||
udev->rx_lanes = USB_EXT_PORT_RX_LANES(ext_portstatus) + 1;
|
||||
udev->tx_lanes = USB_EXT_PORT_TX_LANES(ext_portstatus) + 1;
|
||||
udev->ssp_rate = get_port_ssp_rate(hub->hdev, ext_portstatus);
|
||||
} else {
|
||||
udev->rx_lanes = 1;
|
||||
udev->tx_lanes = 1;
|
||||
udev->ssp_rate = USB_SSP_GEN_UNKNOWN;
|
||||
}
|
||||
if (hub_is_wusb(hub))
|
||||
udev->speed = USB_SPEED_WIRELESS;
|
||||
|
@ -560,6 +560,7 @@ struct usb3_lpm_parameters {
|
||||
* @speed: device speed: high/full/low (or error)
|
||||
* @rx_lanes: number of rx lanes in use, USB 3.2 adds dual-lane support
|
||||
* @tx_lanes: number of tx lanes in use, USB 3.2 adds dual-lane support
|
||||
* @ssp_rate: SuperSpeed Plus phy signaling rate and lane count
|
||||
* @tt: Transaction Translator info; used with low/full speed dev, highspeed hub
|
||||
* @ttport: device port on that tt hub
|
||||
* @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints
|
||||
@ -636,6 +637,7 @@ struct usb_device {
|
||||
enum usb_device_speed speed;
|
||||
unsigned int rx_lanes;
|
||||
unsigned int tx_lanes;
|
||||
enum usb_ssp_rate ssp_rate;
|
||||
|
||||
struct usb_tt *tt;
|
||||
int ttport;
|
||||
|
Loading…
Reference in New Issue
Block a user