diff options
Diffstat (limited to 'drivers/thunderbolt/usb4.c')
-rw-r--r-- | drivers/thunderbolt/usb4.c | 183 |
1 files changed, 98 insertions, 85 deletions
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index de480bf2a53d..4d83b65afb5b 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -17,12 +17,6 @@ #define USB4_DATA_RETRIES 3 #define USB4_DATA_DWORDS 16 -enum usb4_sb_target { - USB4_SB_TARGET_ROUTER, - USB4_SB_TARGET_PARTNER, - USB4_SB_TARGET_RETIMER, -}; - #define USB4_NVM_READ_OFFSET_MASK GENMASK(23, 2) #define USB4_NVM_READ_OFFSET_SHIFT 2 #define USB4_NVM_READ_LENGTH_MASK GENMASK(27, 24) @@ -1289,8 +1283,20 @@ static int usb4_port_write_data(struct tb_port *port, const void *data, dwords); } -static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, - u8 index, u8 reg, void *buf, u8 size) +/** + * usb4_port_sb_read() - Read from sideband register + * @port: USB4 port to read + * @target: Sideband target + * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER + * @reg: Sideband register index + * @buf: Buffer where the sideband data is copied + * @size: Size of @buf + * + * Reads data from sideband register @reg and copies it into @buf. + * Returns %0 in case of success and negative errno in case of failure. + */ +int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index, + u8 reg, void *buf, u8 size) { size_t dwords = DIV_ROUND_UP(size, 4); int ret; @@ -1329,8 +1335,20 @@ static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, return buf ? usb4_port_read_data(port, buf, dwords) : 0; } -static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, - u8 index, u8 reg, const void *buf, u8 size) +/** + * usb4_port_sb_write() - Write to sideband register + * @port: USB4 port to write + * @target: Sideband target + * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER + * @reg: Sideband register index + * @buf: Data to write + * @size: Size of @buf + * + * Writes @buf to sideband register @reg. Returns %0 in case of success + * and negative errno in case of failure. + */ +int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, + u8 index, u8 reg, const void *buf, u8 size) { size_t dwords = DIV_ROUND_UP(size, 4); int ret; @@ -1610,26 +1628,31 @@ int usb4_port_asym_start(struct tb_port *port) /** * usb4_port_margining_caps() - Read USB4 port marginig capabilities * @port: USB4 port + * @target: Sideband target + * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @caps: Array with at least two elements to hold the results * * Reads the USB4 port lane margining capabilities into @caps. */ -int usb4_port_margining_caps(struct tb_port *port, u32 *caps) +int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, + u8 index, u32 *caps) { int ret; - ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + ret = usb4_port_sb_op(port, target, index, USB4_SB_OPCODE_READ_LANE_MARGINING_CAP, 500); if (ret) return ret; - return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0, - USB4_SB_DATA, caps, sizeof(*caps) * 2); + return usb4_port_sb_read(port, target, index, USB4_SB_DATA, caps, + sizeof(*caps) * 2); } /** * usb4_port_hw_margin() - Run hardware lane margining on port * @port: USB4 port + * @target: Sideband target + * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @lanes: Which lanes to run (must match the port capabilities). Can be * %0, %1 or %7. * @ber_level: BER level contour value @@ -1640,9 +1663,9 @@ int usb4_port_margining_caps(struct tb_port *port, u32 *caps) * Runs hardware lane margining on USB4 port and returns the result in * @results. */ -int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes, - unsigned int ber_level, bool timing, bool right_high, - u32 *results) +int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, + u8 index, unsigned int lanes, unsigned int ber_level, + bool timing, bool right_high, u32 *results) { u32 val; int ret; @@ -1656,23 +1679,25 @@ int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes, val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) & USB4_MARGIN_HW_BER_MASK; - ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0, - USB4_SB_METADATA, &val, sizeof(val)); + ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val, + sizeof(val)); if (ret) return ret; - ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + ret = usb4_port_sb_op(port, target, index, USB4_SB_OPCODE_RUN_HW_LANE_MARGINING, 2500); if (ret) return ret; - return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0, - USB4_SB_DATA, results, sizeof(*results) * 2); + return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results, + sizeof(*results) * 2); } /** * usb4_port_sw_margin() - Run software lane margining on port * @port: USB4 port + * @target: Sideband target + * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @lanes: Which lanes to run (must match the port capabilities). Can be * %0, %1 or %7. * @timing: Perform timing margining instead of voltage @@ -1683,7 +1708,8 @@ int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes, * counters by calling usb4_port_sw_margin_errors(). Returns %0 in * success and negative errno otherwise. */ -int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing, +int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target, + u8 index, unsigned int lanes, bool timing, bool right_high, u32 counter) { u32 val; @@ -1697,34 +1723,37 @@ int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing, val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) & USB4_MARGIN_SW_COUNTER_MASK; - ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0, - USB4_SB_METADATA, &val, sizeof(val)); + ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val, + sizeof(val)); if (ret) return ret; - return usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + return usb4_port_sb_op(port, target, index, USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500); } /** * usb4_port_sw_margin_errors() - Read the software margining error counters * @port: USB4 port + * @target: Sideband target + * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @errors: Error metadata is copied here. * * This reads back the software margining error counters from the port. * Returns %0 in success and negative errno otherwise. */ -int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors) +int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target, + u8 index, u32 *errors) { int ret; - ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + ret = usb4_port_sb_op(port, target, index, USB4_SB_OPCODE_READ_SW_MARGIN_ERR, 150); if (ret) return ret; - return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0, - USB4_SB_METADATA, errors, sizeof(*errors)); + return usb4_port_sb_read(port, target, index, USB4_SB_METADATA, errors, + sizeof(*errors)); } static inline int usb4_port_retimer_op(struct tb_port *port, u8 index, @@ -1777,68 +1806,51 @@ int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index) } /** - * usb4_port_retimer_read() - Read from retimer sideband registers + * usb4_port_retimer_is_last() - Is the retimer last on-board retimer * @port: USB4 port * @index: Retimer index - * @reg: Sideband register to read - * @buf: Data from @reg is stored here - * @size: Number of bytes to read * - * Function reads retimer sideband registers starting from @reg. The - * retimer is connected to @port at @index. Returns %0 in case of - * success, and read data is copied to @buf. If there is no retimer - * present at given @index returns %-ENODEV. In any other failure - * returns negative errno. + * If the retimer at @index is last one (connected directly to the + * Type-C port) this function returns %1. If it is not returns %0. If + * the retimer is not present returns %-ENODEV. Otherwise returns + * negative errno. */ -int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf, - u8 size) +int usb4_port_retimer_is_last(struct tb_port *port, u8 index) { - return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, reg, buf, - size); -} + u32 metadata; + int ret; -/** - * usb4_port_retimer_write() - Write to retimer sideband registers - * @port: USB4 port - * @index: Retimer index - * @reg: Sideband register to write - * @buf: Data that is written starting from @reg - * @size: Number of bytes to write - * - * Writes retimer sideband registers starting from @reg. The retimer is - * connected to @port at @index. Returns %0 in case of success. If there - * is no retimer present at given @index returns %-ENODEV. In any other - * failure returns negative errno. - */ -int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg, - const void *buf, u8 size) -{ - return usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, reg, buf, - size); + ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_LAST_RETIMER, + 500); + if (ret) + return ret; + + ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_METADATA, &metadata, sizeof(metadata)); + return ret ? ret : metadata & 1; } /** - * usb4_port_retimer_is_last() - Is the retimer last on-board retimer + * usb4_port_retimer_is_cable() - Is the retimer cable retimer * @port: USB4 port * @index: Retimer index * - * If the retimer at @index is last one (connected directly to the - * Type-C port) this function returns %1. If it is not returns %0. If - * the retimer is not present returns %-ENODEV. Otherwise returns - * negative errno. + * If the retimer at @index is last cable retimer this function returns + * %1 and %0 if it is on-board retimer. In case a retimer is not present + * at @index returns %-ENODEV. Otherwise returns negative errno. */ -int usb4_port_retimer_is_last(struct tb_port *port, u8 index) +int usb4_port_retimer_is_cable(struct tb_port *port, u8 index) { u32 metadata; int ret; - ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_LAST_RETIMER, + ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_CABLE_RETIMER, 500); if (ret) return ret; - ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata, - sizeof(metadata)); + ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_METADATA, &metadata, sizeof(metadata)); return ret ? ret : metadata & 1; } @@ -1863,8 +1875,8 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index) if (ret) return ret; - ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata, - sizeof(metadata)); + ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_METADATA, &metadata, sizeof(metadata)); return ret ? ret : metadata & USB4_NVM_SECTOR_SIZE_MASK; } @@ -1889,8 +1901,8 @@ int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index, metadata = (dwaddress << USB4_NVM_SET_OFFSET_SHIFT) & USB4_NVM_SET_OFFSET_MASK; - ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata, - sizeof(metadata)); + ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_METADATA, &metadata, sizeof(metadata)); if (ret) return ret; @@ -1912,8 +1924,8 @@ static int usb4_port_retimer_nvm_write_next_block(void *data, u8 index = info->index; int ret; - ret = usb4_port_retimer_write(port, index, USB4_SB_DATA, - buf, dwords * 4); + ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_DATA, buf, dwords * 4); if (ret) return ret; @@ -1992,8 +2004,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, u32 metadata, val; int ret; - ret = usb4_port_retimer_read(port, index, USB4_SB_OPCODE, &val, - sizeof(val)); + ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_OPCODE, &val, sizeof(val)); if (ret) return ret; @@ -2004,8 +2016,9 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, return 0; case -EAGAIN: - ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, - &metadata, sizeof(metadata)); + ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_METADATA, &metadata, + sizeof(metadata)); if (ret) return ret; @@ -2030,8 +2043,8 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress, if (dwords < USB4_DATA_DWORDS) metadata |= dwords << USB4_NVM_READ_LENGTH_SHIFT; - ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata, - sizeof(metadata)); + ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_METADATA, &metadata, sizeof(metadata)); if (ret) return ret; @@ -2039,8 +2052,8 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress, if (ret) return ret; - return usb4_port_retimer_read(port, index, USB4_SB_DATA, buf, - dwords * 4); + return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_DATA, buf, dwords * 4); } /** |