Commit 7bf0fc5a authored by Thinh Nguyen's avatar Thinh Nguyen Committed by Greg Kroah-Hartman
Browse files

usb: gadget: composite: Report various SSP sublink speeds



If a gadget supports SuperSpeed Plus, then it may operate in different
sublink speeds. For example, if the gadget supports SuperSpeed Plus
gen2x2, then it can support 2 sublink speeds gen1 and gen2. Inform the
host of these speeds in the BOS descriptor.

Use 1 SSID if the gadget supports up to gen2x1, or not specified:
- SSID 0 for symmetric RX/TX sublink speed of 10 Gbps.

Use 1 SSID if the gadget supports up to gen1x2:
- SSID 0 for symmetric RX/TX sublink speed of 5 Gbps.

Use 2 SSIDs if the gadget supports up to gen2x2:
- SSID 0 for symmetric RX/TX sublink speed of 5 Gbps.
- SSID 1 for symmetric RX/TX sublink speed of 10 Gbps.

Signed-off-by: default avatarThinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/eb0386fdd5d87a858281e8006a72723d3732240f.1610592135.git.Thinh.Nguyen@synopsys.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ead4c124
Loading
Loading
Loading
Loading
+54 −26
Original line number Diff line number Diff line
@@ -735,49 +735,77 @@ static int bos_desc(struct usb_composite_dev *cdev)
	/* The SuperSpeedPlus USB Device Capability descriptor */
	if (gadget_is_superspeed_plus(cdev->gadget)) {
		struct usb_ssp_cap_descriptor *ssp_cap;
		u8 ssac = 1;
		u8 ssic;
		int i;

		ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
		bos->bNumDeviceCaps++;
		if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x2)
			ssac = 3;

		/*
		 * Report typical values.
		 * Paired RX and TX sublink speed attributes share
		 * the same SSID.
		 */
		ssic = (ssac + 1) / 2 - 1;

		ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
		bos->bNumDeviceCaps++;

		le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(1));
		ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(1);
		le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(ssac));
		ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(ssac);
		ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
		ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE;
		ssp_cap->bReserved = 0;
		ssp_cap->wReserved = 0;

		ssp_cap->bmAttributes =
			cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, 1) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, 0));
			cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, ssac) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, ssic));

		ssp_cap->wFunctionalitySupport =
			cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, 0) |
				    FIELD_PREP(USB_SSP_MIN_RX_LANE_COUNT, 1) |
				    FIELD_PREP(USB_SSP_MIN_TX_LANE_COUNT, 1));

		ssp_cap->bmSublinkSpeedAttr[0] =
			cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, 0) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE,
					       USB_SSP_SUBLINK_SPEED_LSE_GBPS) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST,
					       USB_SSP_SUBLINK_SPEED_ST_SYM_RX) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP,
					       USB_SSP_SUBLINK_SPEED_LP_SSP) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, 10));
		/*
		 * Use 1 SSID if the gadget supports up to gen2x1 or not
		 * specified:
		 * - SSID 0 for symmetric RX/TX sublink speed of 10 Gbps.
		 *
		 * Use 1 SSID if the gadget supports up to gen1x2:
		 * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps.
		 *
		 * Use 2 SSIDs if the gadget supports up to gen2x2:
		 * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps.
		 * - SSID 1 for symmetric RX/TX sublink speed of 10 Gbps.
		 */
		for (i = 0; i < ssac + 1; i++) {
			u8 ssid;
			u8 mantissa;
			u8 type;

		ssp_cap->bmSublinkSpeedAttr[1] =
			cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, 0) |
			ssid = i >> 1;

			if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x1 ||
			    cdev->gadget->max_ssp_rate == USB_SSP_GEN_UNKNOWN)
				mantissa = 10;
			else
				mantissa = 5 << ssid;

			if (i % 2)
				type = USB_SSP_SUBLINK_SPEED_ST_SYM_TX;
			else
				type = USB_SSP_SUBLINK_SPEED_ST_SYM_RX;

			ssp_cap->bmSublinkSpeedAttr[i] =
				cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, ssid) |
					    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE,
						       USB_SSP_SUBLINK_SPEED_LSE_GBPS) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST,
					       USB_SSP_SUBLINK_SPEED_ST_SYM_TX) |
					    FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, type) |
					    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP,
						       USB_SSP_SUBLINK_SPEED_LP_SSP) |
				    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, 10));
					    FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, mantissa));
		}
	}

	return le16_to_cpu(bos->wTotalLength);