Re: [RFC PATCH 1/8] usb: core: Track SuperSpeed Plus GenXxY

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Gustavo A. R. Silva wrote:
> Hi,
>
> On 2/1/21 21:42, Thinh Nguyen wrote:
>> 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@xxxxxxxxxxxx>
>> ---
>>  drivers/usb/core/hcd.c |  6 +++-
>>  drivers/usb/core/hub.c | 78 ++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/usb.h    |  2 ++
>>  3 files changed, 85 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
>> index ad5a0f405a75..55de04df3022 100644
>> --- a/drivers/usb/core/hcd.c
>> +++ b/drivers/usb/core/hcd.c
>> @@ -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:
>> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
>> index 7f71218cc1e5..e78b2dd7801a 100644
>> --- a/drivers/usb/core/hub.c
>> +++ b/drivers/usb/core/hub.c
>> @@ -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 @@ int usb_authorize_device(struct usb_device *usb_dev)
>>  	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++) {
> Why a less than or equal to comparison here?
> Why not just a less than comparison (i < ssac) ?
>
> Thanks
> --
> Gustavo

The SSAC here matches with the SSAC (Sublink Speed Attribute Count) from
the USB 3.2 spec. It's zero based. E.g. so SSAC of 3 is 4 number of
Sublink Speed Attributes. That's why "<=".

Thinh

>
>> +		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;
>> diff --git a/include/linux/usb.h b/include/linux/usb.h
>> index 7d72c4e0713c..c334387f950e 100644
>> --- a/include/linux/usb.h
>> +++ b/include/linux/usb.h
>> @@ -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;
>>





[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux