summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2022-12-27 12:55:26 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-04-05 12:23:37 +0300
commit06e04b450bb49f34d859f49c50d6609dd2008f2f (patch)
tree164063980d6f76de4e375dff3701db5fb8dc2c7e
parent32fa53c27ea36b62e4444e7e859a5d03f6189d9e (diff)
downloadlinux-06e04b450bb49f34d859f49c50d6609dd2008f2f.tar.xz
thunderbolt: Use scale field when allocating USB3 bandwidth
commit c82510b1d87bdebfe916048857d2ef46f1778aa5 upstream. When tunneling aggregated USB3 (20 Gb/s) the bandwidth values that are programmed to the ADP_USB3_CS_2 go higher than 4096 and that does not fit anymore to the 12-bit field. Fix this by scaling the value using the scale field accordingly. Fixes: 3b1d8d577ca8 ("thunderbolt: Implement USB3 bandwidth negotiation routines") Cc: stable@vger.kernel.org Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/thunderbolt/usb4.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 0b3a77ade04d..5b45c45e7c5b 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -1636,18 +1636,30 @@ static int usb4_usb3_port_write_allocated_bandwidth(struct tb_port *port,
int downstream_bw)
{
u32 val, ubw, dbw, scale;
- int ret;
+ int ret, max_bw;
- /* Read the used scale, hardware default is 0 */
- ret = tb_port_read(port, &scale, TB_CFG_PORT,
- port->cap_adap + ADP_USB3_CS_3, 1);
+ /* Figure out suitable scale */
+ scale = 0;
+ max_bw = max(upstream_bw, downstream_bw);
+ while (scale < 64) {
+ if (mbps_to_usb3_bw(max_bw, scale) < 4096)
+ break;
+ scale++;
+ }
+
+ if (WARN_ON(scale >= 64))
+ return -EINVAL;
+
+ ret = tb_port_write(port, &scale, TB_CFG_PORT,
+ port->cap_adap + ADP_USB3_CS_3, 1);
if (ret)
return ret;
- scale &= ADP_USB3_CS_3_SCALE_MASK;
ubw = mbps_to_usb3_bw(upstream_bw, scale);
dbw = mbps_to_usb3_bw(downstream_bw, scale);
+ tb_port_dbg(port, "scaled bandwidth %u/%u, scale %u\n", ubw, dbw, scale);
+
ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_adap + ADP_USB3_CS_2, 1);
if (ret)