Merge tag 'thunderbolt-for-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Apr 2023 09:42:44 +0000 (11:42 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Apr 2023 09:42:44 +0000 (11:42 +0200)
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

1  2 
drivers/thunderbolt/nhi.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/usb4.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)
                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;
  
        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;
@@@ -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");
                        }
                }
  
 +              tb_check_quirks(sw);
 +
                tb_switch_default_link_ports(sw);
  
                ret = tb_switch_update_link_attributes(sw);
@@@ -9,6 -9,7 +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 +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)
  {
                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)
                *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)
        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)