diff options
-rw-r--r-- | drivers/thunderbolt/acpi.c | 2 | ||||
-rw-r--r-- | drivers/thunderbolt/ctl.c | 2 | ||||
-rw-r--r-- | drivers/thunderbolt/eeprom.c | 204 | ||||
-rw-r--r-- | drivers/thunderbolt/nhi.c | 3 | ||||
-rw-r--r-- | drivers/thunderbolt/switch.c | 4 | ||||
-rw-r--r-- | drivers/thunderbolt/usb4.c | 52 | ||||
-rw-r--r-- | drivers/thunderbolt/xdomain.c | 24 |
7 files changed, 149 insertions, 142 deletions
diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c index 628225deb8fe..3514bf65b7a4 100644 --- a/drivers/thunderbolt/acpi.c +++ b/drivers/thunderbolt/acpi.c @@ -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; diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 6e7d28e8d81a..3a213322ec7a 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -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; diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index c90d22f56d4e..0f6099c18a94 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -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,85 +613,14 @@ static int usb4_drom_parse(struct tb_switch *sw) return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE); } -/** - * tb_drom_read() - Copy DROM to sw->drom and parse it - * @sw: Router whose DROM to read and parse - * - * This function reads router DROM and if successful parses the entries and - * populates the fields in @sw accordingly. Can be called for any router - * generation. - * - * Returns %0 in case of success and negative errno otherwise. - */ -int tb_drom_read(struct tb_switch *sw) +static int tb_drom_parse(struct tb_switch *sw, u16 size) { - 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; + 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"); - if (retries--) { - msleep(100); - goto read; - } + tb_sw_warn(sw, "DROM size mismatch\n"); + ret = -EIO; goto err; } @@ -675,29 +628,86 @@ parse: switch (header->device_rom_revision) { case 3: - res = usb4_drom_parse(sw); + 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: - res = tb_drom_parse(sw); + ret = tb_drom_parse_v1(sw); break; } - /* If the DROM parsing fails, wait a moment and retry once */ - if (res == -EILSEQ && retries--) { + if (ret) { tb_sw_warn(sw, "parsing DROM failed\n"); - msleep(100); - goto read; + goto err; } - if (!res) - return 0; + return 0; err: kfree(sw->drom); sw->drom = NULL; - return -EIO; + + 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 + * + * This function reads router DROM and if successful parses the entries and + * populates the fields in @sw accordingly. Can be called for any router + * generation. + * + * Returns %0 in case of success and negative errno otherwise. + */ +int tb_drom_read(struct tb_switch *sw) +{ + if (sw->drom) + return 0; + + if (!tb_route(sw)) + return tb_drom_host_read(sw); + return tb_drom_device_read(sw); } diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index cfebec107f3f..d76e923fbc6a 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -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; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index da373ac38285..51e86b5171c7 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -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)) { diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index a0996cb2893c..485b6e430686 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -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); } diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index a48335c95d39..e2b54887d331 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -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); |