]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
thunderbolt: Add link_speed and link_width to XDomain
authorIsaac Hazan <isaac.hazan@intel.com>
Thu, 24 Sep 2020 08:43:58 +0000 (11:43 +0300)
committerMika Westerberg <mika.westerberg@linux.intel.com>
Wed, 11 Nov 2020 07:20:16 +0000 (10:20 +0300)
Link speed and link width are needed for checking expected values in
case of using a loopback service.

Signed-off-by: Isaac Hazan <isaac.hazan@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Yehezkel Bernat <YehezkelShB@gmail.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-bus-thunderbolt
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/xdomain.c
include/linux/thunderbolt.h

index 0b4ab9e4b8f475248ec67d1c9f23e7822331954f..a91b4b24496ef932619dad1a610ef8aaeb86ec39 100644 (file)
@@ -1,3 +1,31 @@
+What:          /sys/bus/thunderbolt/devices/<xdomain>/rx_speed
+Date:          Feb 2021
+KernelVersion: 5.11
+Contact:       Isaac Hazan <isaac.hazan@intel.com>
+Description:   This attribute reports the XDomain RX speed per lane.
+               All RX lanes run at the same speed.
+
+What:          /sys/bus/thunderbolt/devices/<xdomain>/rx_lanes
+Date:          Feb 2021
+KernelVersion: 5.11
+Contact:       Isaac Hazan <isaac.hazan@intel.com>
+Description:   This attribute reports the number of RX lanes the XDomain
+               is using simultaneously through its upstream port.
+
+What:          /sys/bus/thunderbolt/devices/<xdomain>/tx_speed
+Date:          Feb 2021
+KernelVersion: 5.11
+Contact:       Isaac Hazan <isaac.hazan@intel.com>
+Description:   This attribute reports the XDomain TX speed per lane.
+               All TX lanes run at the same speed.
+
+What:          /sys/bus/thunderbolt/devices/<xdomain>/tx_lanes
+Date:          Feb 2021
+KernelVersion: 5.11
+Contact:       Isaac Hazan <isaac.hazan@intel.com>
+Description:   This attribute reports number of TX lanes the XDomain
+               is using simultaneously through its upstream port.
+
 What: /sys/bus/thunderbolt/devices/.../domainX/boot_acl
 Date:          Jun 2018
 KernelVersion: 4.17
index c73bbfe69ba16461cb6a4a593786c104e6f4e6cd..05a36090179059ceadc8e6b8429a06cf368dc3e6 100644 (file)
@@ -932,7 +932,14 @@ int tb_port_get_link_speed(struct tb_port *port)
        return speed == LANE_ADP_CS_1_CURRENT_SPEED_GEN3 ? 20 : 10;
 }
 
-static int tb_port_get_link_width(struct tb_port *port)
+/**
+ * tb_port_get_link_width() - Get current link width
+ * @port: Port to check (USB4 or CIO)
+ *
+ * Returns link width. Return values can be 1 (Single-Lane), 2 (Dual-Lane)
+ * or negative errno in case of failure.
+ */
+int tb_port_get_link_width(struct tb_port *port)
 {
        u32 val;
        int ret;
index a9995e21b9165e6a367697248c51e40cb4435bf3..3a826315049e2079b06f15a083b17bdaa5924de5 100644 (file)
@@ -862,6 +862,7 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
             (p) = tb_next_port_on_path((src), (dst), (p)))
 
 int tb_port_get_link_speed(struct tb_port *port);
+int tb_port_get_link_width(struct tb_port *port);
 
 int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
 int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
index da229ac4e47185d48c0296061324d996c39850cd..83a315f969340399c6cf2ff0f784b04feba42a53 100644 (file)
@@ -942,6 +942,43 @@ static void tb_xdomain_restore_paths(struct tb_xdomain *xd)
        }
 }
 
+static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd)
+{
+       return tb_to_switch(xd->dev.parent);
+}
+
+static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd)
+{
+       bool change = false;
+       struct tb_port *port;
+       int ret;
+
+       port = tb_port_at(xd->route, tb_xdomain_parent(xd));
+
+       ret = tb_port_get_link_speed(port);
+       if (ret < 0)
+               return ret;
+
+       if (xd->link_speed != ret)
+               change = true;
+
+       xd->link_speed = ret;
+
+       ret = tb_port_get_link_width(port);
+       if (ret < 0)
+               return ret;
+
+       if (xd->link_width != ret)
+               change = true;
+
+       xd->link_width = ret;
+
+       if (change)
+               kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE);
+
+       return 0;
+}
+
 static void tb_xdomain_get_uuid(struct work_struct *work)
 {
        struct tb_xdomain *xd = container_of(work, typeof(*xd),
@@ -1053,6 +1090,8 @@ static void tb_xdomain_get_properties(struct work_struct *work)
        xd->properties = dir;
        xd->property_block_gen = gen;
 
+       tb_xdomain_update_link_attributes(xd);
+
        tb_xdomain_restore_paths(xd);
 
        mutex_unlock(&xd->lock);
@@ -1159,9 +1198,35 @@ static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(unique_id);
 
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
+
+       return sprintf(buf, "%u.0 Gb/s\n", xd->link_speed);
+}
+
+static DEVICE_ATTR(rx_speed, 0444, speed_show, NULL);
+static DEVICE_ATTR(tx_speed, 0444, speed_show, NULL);
+
+static ssize_t lanes_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev);
+
+       return sprintf(buf, "%u\n", xd->link_width);
+}
+
+static DEVICE_ATTR(rx_lanes, 0444, lanes_show, NULL);
+static DEVICE_ATTR(tx_lanes, 0444, lanes_show, NULL);
+
 static struct attribute *xdomain_attrs[] = {
        &dev_attr_device.attr,
        &dev_attr_device_name.attr,
+       &dev_attr_rx_lanes.attr,
+       &dev_attr_rx_speed.attr,
+       &dev_attr_tx_lanes.attr,
+       &dev_attr_tx_speed.attr,
        &dev_attr_unique_id.attr,
        &dev_attr_vendor.attr,
        &dev_attr_vendor_name.attr,
index 5db2b11ab0855c102fb20699dbb54c93d52c0664..e441af88ed77f18ab0f0ed4867edec318b3167c4 100644 (file)
@@ -179,6 +179,8 @@ void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir);
  * @lock: Lock to serialize access to the following fields of this structure
  * @vendor_name: Name of the vendor (or %NULL if not known)
  * @device_name: Name of the device (or %NULL if not known)
+ * @link_speed: Speed of the link in Gb/s
+ * @link_width: Width of the link (1 or 2)
  * @is_unplugged: The XDomain is unplugged
  * @resume: The XDomain is being resumed
  * @needs_uuid: If the XDomain does not have @remote_uuid it will be
@@ -223,6 +225,8 @@ struct tb_xdomain {
        struct mutex lock;
        const char *vendor_name;
        const char *device_name;
+       unsigned int link_speed;
+       unsigned int link_width;
        bool is_unplugged;
        bool resume;
        bool needs_uuid;