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:
commit
ced7c981f3
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue