Commit 4210d50f authored by Isaac Hazan's avatar Isaac Hazan Committed by Mika Westerberg
Browse files

thunderbolt: Add link_speed and link_width to XDomain



Link speed and link width are needed for checking expected values in
case of using a loopback service.

Signed-off-by: default avatarIsaac Hazan <isaac.hazan@intel.com>
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: default avatarYehezkel Bernat <YehezkelShB@gmail.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 47844ecb
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
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
+8 −1
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);
+65 −0
Original line number Diff line number Diff line
@@ -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,
+4 −0
Original line number Diff line number Diff line
@@ -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;