From: Greg Kroah-Hartman Date: Wed, 19 Apr 2023 09:42:44 +0000 (+0200) Subject: Merge tag 'thunderbolt-for-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel... X-Git-Tag: v6.6.7~2985^2~45 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ced7c981f382fc34b941ee3b861d49bdd9180af4;hp=-c;p=platform%2Fkernel%2Flinux-starfive.git Merge tag 'thunderbolt-for-v6.4-rc1' of git://git./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 --- ced7c981f382fc34b941ee3b861d49bdd9180af4 diff --combined drivers/thunderbolt/nhi.c index cfebec1,4400e13..d76e923 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@@ -46,7 -46,7 +46,7 @@@ #define QUIRK_AUTO_CLEAR_INT BIT(0) #define QUIRK_E2E BIT(1) -static int ring_interrupt_index(struct tb_ring *ring) +static int ring_interrupt_index(const struct tb_ring *ring) { int bit = ring->hop; if (!ring->is_tx) @@@ -63,14 -63,13 +63,14 @@@ static void ring_interrupt_active(struc { int reg = REG_RING_INTERRUPT_BASE + ring_interrupt_index(ring) / 32 * 4; - int bit = ring_interrupt_index(ring) & 31; - int mask = 1 << bit; + int interrupt_bit = ring_interrupt_index(ring) & 31; + int mask = 1 << interrupt_bit; u32 old, new; if (ring->irq > 0) { u32 step, shift, ivr, misc; void __iomem *ivr_base; + int auto_clear_bit; int index; if (ring->is_tx) @@@ -78,25 -77,18 +78,25 @@@ else index = ring->hop + ring->nhi->hop_count; - if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT) { - /* - * Ask the hardware to clear interrupt status - * bits automatically since we already know - * which interrupt was triggered. - */ - misc = ioread32(ring->nhi->iobase + REG_DMA_MISC); - if (!(misc & REG_DMA_MISC_INT_AUTO_CLEAR)) { - misc |= REG_DMA_MISC_INT_AUTO_CLEAR; - iowrite32(misc, ring->nhi->iobase + REG_DMA_MISC); - } - } + /* + * Intel routers support a bit that isn't part of + * the USB4 spec to ask the hardware to clear + * interrupt status bits automatically since + * we already know which interrupt was triggered. + * + * Other routers explicitly disable auto-clear + * to prevent conditions that may occur where two + * MSIX interrupts are simultaneously active and + * reading the register clears both of them. + */ + misc = ioread32(ring->nhi->iobase + REG_DMA_MISC); + if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT) + auto_clear_bit = REG_DMA_MISC_INT_AUTO_CLEAR; + else + auto_clear_bit = REG_DMA_MISC_DISABLE_AUTO_CLEAR; + if (!(misc & auto_clear_bit)) + iowrite32(misc | auto_clear_bit, + ring->nhi->iobase + REG_DMA_MISC); ivr_base = ring->nhi->iobase + REG_INT_VEC_ALLOC_BASE; step = index / REG_INT_VEC_ALLOC_REGS * REG_INT_VEC_ALLOC_BITS; @@@ -116,7 -108,7 +116,7 @@@ dev_dbg(&ring->nhi->pdev->dev, "%s interrupt at register %#x bit %d (%#x -> %#x)\n", - active ? "enabling" : "disabling", reg, bit, old, new); + active ? "enabling" : "disabling", reg, interrupt_bit, old, new); if (new == old) dev_WARN(&ring->nhi->pdev->dev, @@@ -401,17 -393,14 +401,17 @@@ EXPORT_SYMBOL_GPL(tb_ring_poll_complete static void ring_clear_msix(const struct tb_ring *ring) { + int bit; + if (ring->nhi->quirks & QUIRK_AUTO_CLEAR_INT) return; + bit = ring_interrupt_index(ring) & 31; if (ring->is_tx) - ioread32(ring->nhi->iobase + REG_RING_NOTIFY_BASE); + iowrite32(BIT(bit), ring->nhi->iobase + REG_RING_INT_CLEAR); else - ioread32(ring->nhi->iobase + REG_RING_NOTIFY_BASE + - 4 * (ring->nhi->hop_count / 32)); + iowrite32(BIT(bit), ring->nhi->iobase + REG_RING_INT_CLEAR + + 4 * (ring->nhi->hop_count / 32)); } static irqreturn_t ring_msix(int irq, void *data) @@@ -526,7 -515,8 +526,8 @@@ static int nhi_alloc_hop(struct tb_nhi 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 --combined drivers/thunderbolt/switch.c index da373ac,0a34880..51e86b51 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@@ -271,9 -271,9 +271,9 @@@ static int nvm_authenticate(struct tb_s } 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)) { @@@ -2968,6 -2968,8 +2968,6 @@@ int tb_switch_add(struct tb_switch *sw dev_warn(&sw->dev, "reading DROM failed: %d\n", ret); tb_sw_dbg(sw, "uid: %#llx\n", sw->uid); - tb_check_quirks(sw); - ret = tb_switch_set_uuid(sw); if (ret) { dev_err(&sw->dev, "failed to set UUID\n"); @@@ -2986,8 -2988,6 +2986,8 @@@ } } + tb_check_quirks(sw); + tb_switch_default_link_ports(sw); ret = tb_switch_update_link_attributes(sw); diff --combined drivers/thunderbolt/usb4.c index a0996cb2,bcc3ec2..485b6e4 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@@ -9,6 -9,7 +9,7 @@@ #include #include + #include #include "sb_regs.h" #include "tb.h" @@@ -851,7 -852,7 +852,7 @@@ bool usb4_switch_query_dp_resource(stru */ if (ret == -EOPNOTSUPP) return true; - else if (ret) + if (ret) return false; return !status; @@@ -877,7 -878,7 +878,7 @@@ int usb4_switch_alloc_dp_resource(struc &status); if (ret == -EOPNOTSUPP) return 0; - else if (ret) + if (ret) return ret; return status ? -EBUSY : 0; @@@ -900,7 -901,7 +901,7 @@@ int usb4_switch_dealloc_dp_resource(str &status); if (ret == -EOPNOTSUPP) return 0; - else if (ret) + if (ret) return ret; return status ? -EIO : 0; @@@ -1302,6 -1303,20 +1303,20 @@@ static int usb4_port_sb_write(struct tb 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 +1339,8 @@@ 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; @@@ -1579,20 -1581,6 +1581,20 @@@ int usb4_port_retimer_set_inbound_sbtx( } /** + * usb4_port_retimer_unset_inbound_sbtx() - Disable sideband channel transactions + * @port: USB4 port + * @index: Retimer index + * + * Disables sideband channel transations on SBTX. The reverse of + * usb4_port_retimer_set_inbound_sbtx(). + */ +int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index) +{ + return usb4_port_retimer_op(port, index, + USB4_SB_OPCODE_UNSET_INBOUND_SBTX, 500); +} + +/** * usb4_port_retimer_read() - Read from retimer sideband registers * @port: USB4 port * @index: Retimer index @@@ -1813,12 -1801,13 +1815,13 @@@ int usb4_port_retimer_nvm_authenticate_ 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 -1816,8 +1830,8 @@@ *status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK; return 0; - case USB4_SB_OPCODE_ONS: - return -EOPNOTSUPP; - default: - return -EIO; + return ret; } } @@@ -1882,15 -1868,6 +1882,15 @@@ int usb4_port_retimer_nvm_read(struct t usb4_port_retimer_nvm_read_block, &info); } +static inline unsigned int +usb4_usb3_port_max_bandwidth(const struct tb_port *port, unsigned int bw) +{ + /* Take the possible bandwidth limitation into account */ + if (port->max_bw) + return min(bw, port->max_bw); + return bw; +} + /** * usb4_usb3_port_max_link_rate() - Maximum support USB3 link rate * @port: USB3 adapter port @@@ -1912,9 -1889,7 +1912,9 @@@ int usb4_usb3_port_max_link_rate(struc return ret; lr = (val & ADP_USB3_CS_4_MSLR_MASK) >> ADP_USB3_CS_4_MSLR_SHIFT; - return lr == ADP_USB3_CS_4_MSLR_20G ? 20000 : 10000; + ret = lr == ADP_USB3_CS_4_MSLR_20G ? 20000 : 10000; + + return usb4_usb3_port_max_bandwidth(port, ret); } /** @@@ -1941,9 -1916,7 +1941,9 @@@ int usb4_usb3_port_actual_link_rate(str return 0; lr = val & ADP_USB3_CS_4_ALR_MASK; - return lr == ADP_USB3_CS_4_ALR_20G ? 20000 : 10000; + ret = lr == ADP_USB3_CS_4_ALR_20G ? 20000 : 10000; + + return usb4_usb3_port_max_bandwidth(port, ret); } static int usb4_usb3_port_cm_request(struct tb_port *port, bool request) @@@ -1995,7 -1968,7 +1995,7 @@@ static unsigned int usb3_bw_to_mbps(u3 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 -1976,7 +2003,7 @@@ 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); } @@@ -2094,30 -2067,18 +2094,30 @@@ static int usb4_usb3_port_write_allocat 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)