thunderbolt: Changes for v6.4 merge window

This includes following Thunderbolt/USB4 changes for the v6.4 merge
 window:
 
   - Refactoring of DROM read code paths
   - Convert to use SI units from units.h
   - A couple of cleanups
 
 All these have been in linux-next with no reported issues.
 -----BEGIN PGP SIGNATURE-----
 
 iQJUBAABCgA+FiEEVTdhRGBbNzLrSUBaAP2fSd+ZWKAFAmQ+SE0gHG1pa2Eud2Vz
 dGVyYmVyZ0BsaW51eC5pbnRlbC5jb20ACgkQAP2fSd+ZWKAKqRAAkTJTVDrquLQo
 pVGfYyIKj3xt6HynHYSOqBv9HCj2+xyjMwp67H3uG22f/tTbCTk06xISe+vNrW8r
 i52Ahptt2a3TVJdyPlDRujCCnFRw841QRx0QN9H7FYmPNfJlBKh+yDTZJns9QkIW
 VUh4BgbTv5Ylw3seA1vdTnOWccWKd9LOIXxSSHCL2gvz0vZjOj3SzMHJJ7koVmFE
 yHqHipJaEoQ2GD8na2OPA1wkN06bR1Jg3qW1OiImJFkCrxJwUQ9RreC8lK+ccwF1
 M1NpEcvg4QeGXG4sWUupWz/pLtIK2DnjNbjCbEu8a6MBHiwB1jxBmSFI/48uMWID
 OVmnEZ7utRKv2wGbO5T41XDjFB7fn+kOkNKOkxK78855/0Ed0b10ETRLhPsLtP7R
 QnV9G/fcZPtgOBuqrCSIljLSx89NI+iO3FMtvkLd4/WiCY1UfBG8adouiAtmHvFS
 HfN7ttxmImSKLQ0nGV8s3DceBWqT/l9l46ScJi3MdcOVSIp1TG2PnGXgiXOb3Xo2
 uFD31OqtSgkwQdk9vgdDvBUwTYdF0tYrMgVAkTNi9RfJmpWcpg9IxBTijJkXeqMv
 AoOxNMqH9RCUGEstlo2pH/hheG8pE2QPs1ce2VEzFkDwPztVen6ZbjrKC1HkpQr+
 k7uakIefh419lRXG+4BHGLItW4k5yWg=
 =IcG3
 -----END PGP SIGNATURE-----

Merge tag 'thunderbolt-for-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into usb-next

Mika writes:

thunderbolt: Changes for v6.4 merge window

This includes following Thunderbolt/USB4 changes for the v6.4 merge
window:

  - Refactoring of DROM read code paths
  - Convert to use SI units from units.h
  - A couple of cleanups

All these have been in linux-next with no reported issues.

* tag 'thunderbolt-for-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
  thunderbolt: Introduce usb4_port_sb_opcode_err_to_errno() helper
  thunderbolt: Make use of SI units from units.h
  thunderbolt: Get rid of redundant 'else'
  thunderbolt: Refactor DROM reading
  thunderbolt: use `tb_eeprom_get_drom_offset` to discover DROM offset
This commit is contained in:
Greg Kroah-Hartman 2023-04-19 11:42:44 +02:00
commit ced7c981f3
7 changed files with 160 additions and 153 deletions

View File

@ -341,7 +341,7 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
*/
if (tb_is_switch(dev))
return tb_acpi_switch_find_companion(tb_to_switch(dev));
else if (tb_is_usb4_port_device(dev))
if (tb_is_usb4_port_device(dev))
return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
tb_to_usb4_port_device(dev)->port->port);
return NULL;

View File

@ -1033,7 +1033,7 @@ static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space,
if (res->tb_error == TB_CFG_ERROR_LOCK)
return -EACCES;
else if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED)
if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED)
return -ENOTCONN;
return -EIO;

View File

@ -416,7 +416,7 @@ static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size)
if (pos + 1 == drom_size || pos + entry->len > drom_size
|| !entry->len) {
tb_sw_warn(sw, "DROM buffer overrun\n");
return -EILSEQ;
return -EIO;
}
switch (entry->type) {
@ -471,14 +471,13 @@ err:
static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size)
{
u32 drom_offset;
u16 drom_offset;
int ret;
if (!sw->dma_port)
return -ENODEV;
ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH,
sw->cap_plug_events + 12, 1);
ret = tb_eeprom_get_drom_offset(sw, &drom_offset);
if (ret)
return ret;
@ -513,7 +512,7 @@ err_free:
return ret;
}
static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
static int usb4_copy_drom(struct tb_switch *sw, u16 *size)
{
int ret;
@ -536,15 +535,40 @@ static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size)
return ret;
}
static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val,
size_t count)
static int tb_drom_bit_bang(struct tb_switch *sw, u16 *size)
{
if (tb_switch_is_usb4(sw))
return usb4_switch_drom_read(sw, offset, val, count);
return tb_eeprom_read_n(sw, offset, val, count);
int ret;
ret = tb_eeprom_read_n(sw, 14, (u8 *)size, 2);
if (ret)
return ret;
*size &= 0x3ff;
*size += TB_DROM_DATA_START;
tb_sw_dbg(sw, "reading DROM (length: %#x)\n", *size);
if (*size < sizeof(struct tb_drom_header)) {
tb_sw_warn(sw, "DROM too small, aborting\n");
return -EIO;
}
sw->drom = kzalloc(*size, GFP_KERNEL);
if (!sw->drom)
return -ENOMEM;
ret = tb_eeprom_read_n(sw, 0, sw->drom, *size);
if (ret)
goto err;
return 0;
err:
kfree(sw->drom);
sw->drom = NULL;
return ret;
}
static int tb_drom_parse(struct tb_switch *sw)
static int tb_drom_parse_v1(struct tb_switch *sw)
{
const struct tb_drom_header *header =
(const struct tb_drom_header *)sw->drom;
@ -555,7 +579,7 @@ static int tb_drom_parse(struct tb_switch *sw)
tb_sw_warn(sw,
"DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n",
header->uid_crc8, crc);
return -EILSEQ;
return -EIO;
}
if (!sw->uid)
sw->uid = header->uid;
@ -589,6 +613,85 @@ static int usb4_drom_parse(struct tb_switch *sw)
return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE);
}
static int tb_drom_parse(struct tb_switch *sw, u16 size)
{
const struct tb_drom_header *header = (const void *)sw->drom;
int ret;
if (header->data_len + TB_DROM_DATA_START != size) {
tb_sw_warn(sw, "DROM size mismatch\n");
ret = -EIO;
goto err;
}
tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision);
switch (header->device_rom_revision) {
case 3:
ret = usb4_drom_parse(sw);
break;
default:
tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n",
header->device_rom_revision);
fallthrough;
case 1:
ret = tb_drom_parse_v1(sw);
break;
}
if (ret) {
tb_sw_warn(sw, "parsing DROM failed\n");
goto err;
}
return 0;
err:
kfree(sw->drom);
sw->drom = NULL;
return ret;
}
static int tb_drom_host_read(struct tb_switch *sw)
{
u16 size;
if (tb_switch_is_usb4(sw)) {
usb4_switch_read_uid(sw, &sw->uid);
if (!usb4_copy_drom(sw, &size))
return tb_drom_parse(sw, size);
} else {
if (!tb_drom_copy_efi(sw, &size))
return tb_drom_parse(sw, size);
if (!tb_drom_copy_nvm(sw, &size))
return tb_drom_parse(sw, size);
tb_drom_read_uid_only(sw, &sw->uid);
}
return 0;
}
static int tb_drom_device_read(struct tb_switch *sw)
{
u16 size;
int ret;
if (tb_switch_is_usb4(sw)) {
usb4_switch_read_uid(sw, &sw->uid);
ret = usb4_copy_drom(sw, &size);
} else {
ret = tb_drom_bit_bang(sw, &size);
}
if (ret)
return ret;
return tb_drom_parse(sw, size);
}
/**
* tb_drom_read() - Copy DROM to sw->drom and parse it
* @sw: Router whose DROM to read and parse
@ -601,103 +704,10 @@ static int usb4_drom_parse(struct tb_switch *sw)
*/
int tb_drom_read(struct tb_switch *sw)
{
u16 size;
struct tb_drom_header *header;
int res, retries = 1;
if (sw->drom)
return 0;
if (tb_route(sw) == 0) {
/*
* Apple's NHI EFI driver supplies a DROM for the root switch
* in a device property. Use it if available.
*/
if (tb_drom_copy_efi(sw, &size) == 0)
goto parse;
/* Non-Apple hardware has the DROM as part of NVM */
if (tb_drom_copy_nvm(sw, &size) == 0)
goto parse;
/*
* USB4 hosts may support reading DROM through router
* operations.
*/
if (tb_switch_is_usb4(sw)) {
usb4_switch_read_uid(sw, &sw->uid);
if (!usb4_copy_host_drom(sw, &size))
goto parse;
} else {
/*
* The root switch contains only a dummy drom
* (header only, no entries). Hardcode the
* configuration here.
*/
tb_drom_read_uid_only(sw, &sw->uid);
}
return 0;
}
res = tb_drom_read_n(sw, 14, (u8 *) &size, 2);
if (res)
return res;
size &= 0x3ff;
size += TB_DROM_DATA_START;
tb_sw_dbg(sw, "reading drom (length: %#x)\n", size);
if (size < sizeof(*header)) {
tb_sw_warn(sw, "drom too small, aborting\n");
return -EIO;
}
sw->drom = kzalloc(size, GFP_KERNEL);
if (!sw->drom)
return -ENOMEM;
read:
res = tb_drom_read_n(sw, 0, sw->drom, size);
if (res)
goto err;
parse:
header = (void *) sw->drom;
if (header->data_len + TB_DROM_DATA_START != size) {
tb_sw_warn(sw, "drom size mismatch\n");
if (retries--) {
msleep(100);
goto read;
}
goto err;
}
tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision);
switch (header->device_rom_revision) {
case 3:
res = usb4_drom_parse(sw);
break;
default:
tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n",
header->device_rom_revision);
fallthrough;
case 1:
res = tb_drom_parse(sw);
break;
}
/* If the DROM parsing fails, wait a moment and retry once */
if (res == -EILSEQ && retries--) {
tb_sw_warn(sw, "parsing DROM failed\n");
msleep(100);
goto read;
}
if (!res)
return 0;
err:
kfree(sw->drom);
sw->drom = NULL;
return -EIO;
if (!tb_route(sw))
return tb_drom_host_read(sw);
return tb_drom_device_read(sw);
}

View File

@ -526,7 +526,8 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring)
ring->hop);
ret = -EBUSY;
goto err_unlock;
} else if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
}
if (!ring->is_tx && nhi->rx_rings[ring->hop]) {
dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n",
ring->hop);
ret = -EBUSY;

View File

@ -271,9 +271,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
}
sw->nvm->authenticating = true;
return usb4_switch_nvm_authenticate(sw);
} else if (auth_only) {
return -EOPNOTSUPP;
}
if (auth_only)
return -EOPNOTSUPP;
sw->nvm->authenticating = true;
if (!tb_route(sw)) {

View File

@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/units.h>
#include "sb_regs.h"
#include "tb.h"
@ -851,7 +852,7 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in)
*/
if (ret == -EOPNOTSUPP)
return true;
else if (ret)
if (ret)
return false;
return !status;
@ -877,7 +878,7 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
&status);
if (ret == -EOPNOTSUPP)
return 0;
else if (ret)
if (ret)
return ret;
return status ? -EBUSY : 0;
@ -900,7 +901,7 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
&status);
if (ret == -EOPNOTSUPP)
return 0;
else if (ret)
if (ret)
return ret;
return status ? -EIO : 0;
@ -1302,6 +1303,20 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
return 0;
}
static int usb4_port_sb_opcode_err_to_errno(u32 val)
{
switch (val) {
case 0:
return 0;
case USB4_SB_OPCODE_ERR:
return -EAGAIN;
case USB4_SB_OPCODE_ONS:
return -EOPNOTSUPP;
default:
return -EIO;
}
}
static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
u8 index, enum usb4_sb_opcode opcode, int timeout_msec)
{
@ -1324,21 +1339,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
if (ret)
return ret;
switch (val) {
case 0:
return 0;
case USB4_SB_OPCODE_ERR:
return -EAGAIN;
case USB4_SB_OPCODE_ONS:
return -EOPNOTSUPP;
default:
if (val != opcode)
return -EIO;
break;
}
if (val != opcode)
return usb4_port_sb_opcode_err_to_errno(val);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
@ -1813,12 +1815,13 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
if (ret)
return ret;
switch (val) {
ret = usb4_port_sb_opcode_err_to_errno(val);
switch (ret) {
case 0:
*status = 0;
return 0;
case USB4_SB_OPCODE_ERR:
case -EAGAIN:
ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA,
&metadata, sizeof(metadata));
if (ret)
@ -1827,11 +1830,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
*status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK;
return 0;
case USB4_SB_OPCODE_ONS:
return -EOPNOTSUPP;
default:
return -EIO;
return ret;
}
}
@ -1995,7 +1995,7 @@ static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale)
unsigned long uframes;
uframes = bw * 512UL << scale;
return DIV_ROUND_CLOSEST(uframes * 8000, 1000 * 1000);
return DIV_ROUND_CLOSEST(uframes * 8000, MEGA);
}
static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale)
@ -2003,7 +2003,7 @@ static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale)
unsigned long uframes;
/* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */
uframes = ((unsigned long)mbps * 1000 * 1000) / 8000;
uframes = ((unsigned long)mbps * MEGA) / 8000;
return DIV_ROUND_UP(uframes, 512UL << scale);
}

View File

@ -1178,9 +1178,8 @@ static int tb_xdomain_get_uuid(struct tb_xdomain *xd)
if (xd->state_retries-- > 0) {
dev_dbg(&xd->dev, "failed to request UUID, retrying\n");
return -EAGAIN;
} else {
dev_dbg(&xd->dev, "failed to read remote UUID\n");
}
dev_dbg(&xd->dev, "failed to read remote UUID\n");
return ret;
}
@ -1367,12 +1366,10 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
dev_dbg(&xd->dev,
"failed to request remote properties, retrying\n");
return -EAGAIN;
} else {
/* Give up now */
dev_err(&xd->dev,
"failed read XDomain properties from %pUb\n",
xd->remote_uuid);
}
/* Give up now */
dev_err(&xd->dev, "failed read XDomain properties from %pUb\n",
xd->remote_uuid);
return ret;
}
@ -2179,13 +2176,12 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
if (xd->remote_uuid &&
uuid_equal(xd->remote_uuid, lookup->uuid))
return xd;
} else if (lookup->link &&
lookup->link == xd->link &&
lookup->depth == xd->depth) {
return xd;
} else if (lookup->route &&
lookup->route == xd->route) {
return xd;
} else {
if (lookup->link && lookup->link == xd->link &&
lookup->depth == xd->depth)
return xd;
if (lookup->route && lookup->route == xd->route)
return xd;
}
} else if (tb_port_has_remote(port)) {
xd = switch_find_xdomain(port->remote->sw, lookup);