Commit e0d07ba7 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'thunderbolt-for-v5.17-rc1' of...

Merge tag 'thunderbolt-for-v5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into usb-next

Mika writes:

thunderbolt: Changes for v5.17 merge window

This includes following Thunderbolt/USB4 changes for the v5.17 merge
window:

  * Enable low-power link state (CL0s) for USB4 and Intel Titan Ridge
    devices
  * Add support for TMU (Time Management Unit) uni-directional mode
  * Power management improvements (suspend-to-disk, runtime PM)
  * USB4 compatibility fixes
  * Minor fixes and cleanups.

All these have been in linux-next with no reported issues.

* tag 'thunderbolt-for-v5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
  thunderbolt: Add module parameter for CLx disabling
  thunderbolt: Enable CL0s for Intel Titan Ridge
  thunderbolt: Rename Intel TB_VSE_CAP_IECS capability
  thunderbolt: Implement TMU time disruption for Intel Titan Ridge
  thunderbolt: Move usb4_switch_wait_for_bit() to switch.c
  thunderbolt: Add CL0s support for USB4 routers
  thunderbolt: Add TMU uni-directional mode
  thunderbolt: Check return value of kmemdup() in icm_handle_event()
  thunderbolt: Do not dereference fwnode in struct device
  thunderbolt: Add debug logging of DisplayPort resource allocation
  thunderbolt: Do not program path HopIDs for USB4 routers
  thunderbolt: Do not allow subtracting more NFC credits than configured
  thunderbolt: Runtime resume USB4 port when retimers are scanned
  thunderbolt: Tear down existing tunnels when resuming from hibernate
  thunderbolt: Runtime PM activate both ends of the device link
  thunderbolt: xdomain: Avoid potential stack OOB read
parents e681a9d2 fa487b2a
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */

#include <linux/acpi.h>
#include <linux/pm_runtime.h>

#include "tb.h"

@@ -31,7 +32,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
		return AE_OK;

	/* It needs to reference this NHI */
	if (nhi->pdev->dev.fwnode != args.fwnode)
	if (dev_fwnode(&nhi->pdev->dev) != args.fwnode)
		goto out_put;

	/*
@@ -74,8 +75,18 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
		 pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))) {
		const struct device_link *link;

		/*
		 * Make them both active first to make sure the NHI does
		 * not runtime suspend before the consumer. The
		 * pm_runtime_put() below then allows the consumer to
		 * runtime suspend again (which then allows NHI runtime
		 * suspend too now that the device link is established).
		 */
		pm_runtime_get_sync(&pdev->dev);

		link = device_link_add(&pdev->dev, &nhi->pdev->dev,
				       DL_FLAG_AUTOREMOVE_SUPPLIER |
				       DL_FLAG_RPM_ACTIVE |
				       DL_FLAG_PM_RUNTIME);
		if (link) {
			dev_dbg(&nhi->pdev->dev, "created link from %s\n",
@@ -84,6 +95,8 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
			dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
				 dev_name(&pdev->dev));
		}

		pm_runtime_put(&pdev->dev);
	}

out_put:
+6 −1
Original line number Diff line number Diff line
@@ -1741,8 +1741,13 @@ static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
	if (!n)
		return;

	INIT_WORK(&n->work, icm_handle_notification);
	n->pkg = kmemdup(buf, size, GFP_KERNEL);
	if (!n->pkg) {
		kfree(n);
		return;
	}

	INIT_WORK(&n->work, icm_handle_notification);
	n->tb = tb;

	queue_work(tb->wq, &n->work);
+24 −0
Original line number Diff line number Diff line
@@ -193,6 +193,30 @@ int tb_lc_start_lane_initialization(struct tb_port *port)
	return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
}

/**
 * tb_lc_is_clx_supported() - Check whether CLx is supported by the lane adapter
 * @port: Lane adapter
 *
 * TB_LC_LINK_ATTR_CPS bit reflects if the link supports CLx including
 * active cables (if connected on the link).
 */
bool tb_lc_is_clx_supported(struct tb_port *port)
{
	struct tb_switch *sw = port->sw;
	int cap, ret;
	u32 val;

	cap = find_port_lc_cap(port);
	if (cap < 0)
		return false;

	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_ATTR, 1);
	if (ret)
		return false;

	return !!(val & TB_LC_LINK_ATTR_CPS);
}

static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
			      unsigned int flags)
{
+25 −17
Original line number Diff line number Diff line
@@ -85,11 +85,12 @@ static int tb_path_find_src_hopid(struct tb_port *src,
 * @dst_hopid: HopID to the @dst (%-1 if don't care)
 * @last: Last port is filled here if not %NULL
 * @name: Name of the path
 * @alloc_hopid: Allocate HopIDs for the ports
 *
 * Follows a path starting from @src and @src_hopid to the last output
 * port of the path. Allocates HopIDs for the visited ports. Call
 * tb_path_free() to release the path and allocated HopIDs when the path
 * is not needed anymore.
 * port of the path. Allocates HopIDs for the visited ports (if
 * @alloc_hopid is true). Call tb_path_free() to release the path and
 * allocated HopIDs when the path is not needed anymore.
 *
 * Note function discovers also incomplete paths so caller should check
 * that the @dst port is the expected one. If it is not, the path can be
@@ -99,7 +100,8 @@ static int tb_path_find_src_hopid(struct tb_port *src,
 */
struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
				 struct tb_port *dst, int dst_hopid,
				 struct tb_port **last, const char *name)
				 struct tb_port **last, const char *name,
				 bool alloc_hopid)
{
	struct tb_port *out_port;
	struct tb_regs_hop hop;
@@ -156,6 +158,7 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
	path->tb = src->sw->tb;
	path->path_length = num_hops;
	path->activated = true;
	path->alloc_hopid = alloc_hopid;

	path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL);
	if (!path->hops) {
@@ -177,13 +180,14 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
			goto err;
		}

		if (tb_port_alloc_in_hopid(p, h, h) < 0)
		if (alloc_hopid && tb_port_alloc_in_hopid(p, h, h) < 0)
			goto err;

		out_port = &sw->ports[hop.out_port];
		next_hop = hop.next_hop;

		if (tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) {
		if (alloc_hopid &&
		    tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) {
			tb_port_release_in_hopid(p, h);
			goto err;
		}
@@ -263,6 +267,8 @@ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid,
		return NULL;
	}

	path->alloc_hopid = true;

	in_hopid = src_hopid;
	out_port = NULL;

@@ -345,6 +351,7 @@ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid,
 */
void tb_path_free(struct tb_path *path)
{
	if (path->alloc_hopid) {
		int i;

		for (i = 0; i < path->path_length; i++) {
@@ -357,6 +364,7 @@ void tb_path_free(struct tb_path *path)
				tb_port_release_out_hopid(hop->out_port,
							  hop->next_hop_index);
		}
	}

	kfree(path->hops);
	kfree(path);
+18 −10
Original line number Diff line number Diff line
@@ -324,15 +324,10 @@ struct device_type tb_retimer_type = {

static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
{
	struct usb4_port *usb4;
	struct tb_retimer *rt;
	u32 vendor, device;
	int ret;

	usb4 = port->usb4;
	if (!usb4)
		return -EINVAL;

	ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor,
				     sizeof(vendor));
	if (ret) {
@@ -374,7 +369,7 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
	rt->port = port;
	rt->tb = port->sw->tb;

	rt->dev.parent = &usb4->dev;
	rt->dev.parent = &port->usb4->dev;
	rt->dev.bus = &tb_bus_type;
	rt->dev.type = &tb_retimer_type;
	dev_set_name(&rt->dev, "%s:%u.%u", dev_name(&port->sw->dev),
@@ -453,6 +448,13 @@ int tb_retimer_scan(struct tb_port *port, bool add)
{
	u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
	int ret, i, last_idx = 0;
	struct usb4_port *usb4;

	usb4 = port->usb4;
	if (!usb4)
		return 0;

	pm_runtime_get_sync(&usb4->dev);

	/*
	 * Send broadcast RT to make sure retimer indices facing this
@@ -460,7 +462,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
	 */
	ret = usb4_port_enumerate_retimers(port);
	if (ret)
		return ret;
		goto out;

	/*
	 * Enable sideband channel for each retimer. We can do this
@@ -490,8 +492,10 @@ int tb_retimer_scan(struct tb_port *port, bool add)
			break;
	}

	if (!last_idx)
		return 0;
	if (!last_idx) {
		ret = 0;
		goto out;
	}

	/* Add on-board retimers if they do not exist already */
	for (i = 1; i <= last_idx; i++) {
@@ -507,7 +511,11 @@ int tb_retimer_scan(struct tb_port *port, bool add)
		}
	}

	return 0;
out:
	pm_runtime_mark_last_busy(&usb4->dev);
	pm_runtime_put_autosuspend(&usb4->dev);

	return ret;
}

static int remove_retimer(struct device *dev, void *data)
Loading