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

Merge tag 'thunderbolt-for-v6.8-rc1' of...

Merge tag 'thunderbolt-for-v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into char-misc-next

Mika writes:

thunderbolt: Changes for v6.8 merge window

This includes following USB4/Thunderbolt changes for the v6.8 merge
window:

  - Intel Lunar Lake support
  - PCIe tunneling improvements
  - DisplayPort tunneling improvements
  - Asymmetric switching improvements
  - Couple of minor fixes and cleanups.

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

* tag 'thunderbolt-for-v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
  thunderbolt: Reduce retry timeout to speed up boot for some devices
  thunderbolt: Keep link as asymmetric if preferred by hardware
  thunderbolt: Add support for Intel Lunar Lake
  thunderbolt: Disable PCIe extended encapsulation upon teardown properly
  thunderbolt: Make PCIe tunnel setup and teardown follow CM guide
  thunderbolt: Improve logging when DisplayPort resource is added due to hotplug
  thunderbolt: Use tb_dp_read_cap() to read DP_COMMON_CAP as well
  thunderbolt: Disable CL states only when actually needed
  thunderbolt: Transition link to asymmetric only when both sides support it
  thunderbolt: Log XDomain link speed and width
  thunderbolt: Move width_name() helper to tb.h
  thunderbolt: Handle lane bonding of Gen 4 XDomain links properly
  thunderbolt: Unwind TMU configuration if tb_switch_set_tmu_mode_params() fails
  thunderbolt: Remove duplicated re-assignment of pointer 'out'
parents 1760bfa7 04b99eac
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1020,7 +1020,7 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,

	memset(&reply, 0, sizeof(reply));
	ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
			  1, 10, 2000);
			  1, 10, 250);
	if (ret)
		return ret;

+4 −0
Original line number Diff line number Diff line
@@ -1517,6 +1517,10 @@ static struct pci_device_id nhi_ids[] = {
	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1),
	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI0),
	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI1),
	  .driver_data = (kernel_ulong_t)&icl_nhi_ops },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI) },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI) },

+2 −0
Original line number Diff line number Diff line
@@ -90,6 +90,8 @@ extern const struct tb_nhi_ops icl_nhi_ops;
#define PCI_DEVICE_ID_INTEL_TGL_H_NHI1			0x9a21
#define PCI_DEVICE_ID_INTEL_RPL_NHI0			0xa73e
#define PCI_DEVICE_ID_INTEL_RPL_NHI1			0xa76d
#define PCI_DEVICE_ID_INTEL_LNL_NHI0			0xa833
#define PCI_DEVICE_ID_INTEL_LNL_NHI1			0xa834

#define PCI_CLASS_SERIAL_USB_USB4			0x0c0340

+15 −18
Original line number Diff line number Diff line
@@ -941,22 +941,6 @@ int tb_port_get_link_generation(struct tb_port *port)
	}
}

static const char *width_name(enum tb_link_width width)
{
	switch (width) {
	case TB_LINK_WIDTH_SINGLE:
		return "symmetric, single lane";
	case TB_LINK_WIDTH_DUAL:
		return "symmetric, dual lanes";
	case TB_LINK_WIDTH_ASYM_TX:
		return "asymmetric, 3 transmitters, 1 receiver";
	case TB_LINK_WIDTH_ASYM_RX:
		return "asymmetric, 3 receivers, 1 transmitter";
	default:
		return "unknown";
	}
}

/**
 * tb_port_get_link_width() - Get current link width
 * @port: Port to check (USB4 or CIO)
@@ -2769,7 +2753,7 @@ static void tb_switch_link_init(struct tb_switch *sw)
		return;

	tb_sw_dbg(sw, "current link speed %u.0 Gb/s\n", sw->link_speed);
	tb_sw_dbg(sw, "current link width %s\n", width_name(sw->link_width));
	tb_sw_dbg(sw, "current link width %s\n", tb_width_name(sw->link_width));

	bonded = sw->link_width >= TB_LINK_WIDTH_DUAL;

@@ -2789,6 +2773,19 @@ static void tb_switch_link_init(struct tb_switch *sw)
	if (down->dual_link_port)
		down->dual_link_port->bonded = bonded;
	tb_port_update_credits(down);

	if (tb_port_get_link_generation(up) < 4)
		return;

	/*
	 * Set the Gen 4 preferred link width. This is what the router
	 * prefers when the link is brought up. If the router does not
	 * support asymmetric link configuration, this also will be set
	 * to TB_LINK_WIDTH_DUAL.
	 */
	sw->preferred_link_width = sw->link_width;
	tb_sw_dbg(sw, "preferred link width %s\n",
		  tb_width_name(sw->preferred_link_width));
}

/**
@@ -3029,7 +3026,7 @@ int tb_switch_set_link_width(struct tb_switch *sw, enum tb_link_width width)

	tb_switch_update_link_attributes(sw);

	tb_sw_dbg(sw, "link width set to %s\n", width_name(width));
	tb_sw_dbg(sw, "link width set to %s\n", tb_width_name(width));
	return ret;
}

+50 −24
Original line number Diff line number Diff line
@@ -513,8 +513,6 @@ static void tb_port_unconfigure_xdomain(struct tb_port *port)
		usb4_port_unconfigure_xdomain(port);
	else
		tb_lc_unconfigure_xdomain(port);

	tb_port_enable(port->dual_link_port);
}

static void tb_scan_xdomain(struct tb_port *port)
@@ -1087,15 +1085,14 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
			     struct tb_port *dst_port, int requested_up,
			     int requested_down)
{
	bool clx = false, clx_disabled = false, downstream;
	struct tb_switch *sw;
	bool clx, downstream;
	struct tb_port *up;
	int ret = 0;

	if (!asym_threshold)
		return 0;

	/* Disable CL states before doing any transitions */
	downstream = tb_port_path_direction_downstream(src_port, dst_port);
	/* Pick up router deepest in the hierarchy */
	if (downstream)
@@ -1103,11 +1100,10 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
	else
		sw = src_port->sw;

	clx = tb_disable_clx(sw);

	tb_for_each_upstream_port_on_path(src_port, dst_port, up) {
		struct tb_port *down = tb_switch_downstream_port(up->sw);
		enum tb_link_width width_up, width_down;
		int consumed_up, consumed_down;
		enum tb_link_width width;

		ret = tb_consumed_dp_bandwidth(tb, src_port, dst_port, up,
					       &consumed_up, &consumed_down);
@@ -1128,7 +1124,8 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
			if (consumed_down + requested_down < asym_threshold)
				continue;

			width = TB_LINK_WIDTH_ASYM_RX;
			width_up = TB_LINK_WIDTH_ASYM_RX;
			width_down = TB_LINK_WIDTH_ASYM_TX;
		} else {
			/* Upstream, the opposite of above */
			if (consumed_down + requested_down >= TB_ASYM_MIN) {
@@ -1138,22 +1135,34 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
			if (consumed_up + requested_up < asym_threshold)
				continue;

			width = TB_LINK_WIDTH_ASYM_TX;
			width_up = TB_LINK_WIDTH_ASYM_TX;
			width_down = TB_LINK_WIDTH_ASYM_RX;
		}

		if (up->sw->link_width == width)
		if (up->sw->link_width == width_up)
			continue;

		if (!tb_port_width_supported(up, width))
		if (!tb_port_width_supported(up, width_up) ||
		    !tb_port_width_supported(down, width_down))
			continue;

		/*
		 * Disable CL states before doing any transitions. We
		 * delayed it until now that we know there is a real
		 * transition taking place.
		 */
		if (!clx_disabled) {
			clx = tb_disable_clx(sw);
			clx_disabled = true;
		}

		tb_sw_dbg(up->sw, "configuring asymmetric link\n");

		/*
		 * Here requested + consumed > threshold so we need to
		 * transtion the link into asymmetric now.
		 */
		ret = tb_switch_set_link_width(up->sw, width);
		ret = tb_switch_set_link_width(up->sw, width_up);
		if (ret) {
			tb_sw_warn(up->sw, "failed to set link width\n");
			break;
@@ -1174,24 +1183,24 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
 * @dst_port: Destination adapter
 * @requested_up: New lower bandwidth request upstream (Mb/s)
 * @requested_down: New lower bandwidth request downstream (Mb/s)
 * @keep_asym: Keep asymmetric link if preferred
 *
 * Goes over each link from @src_port to @dst_port and tries to
 * transition the link to symmetric if the currently consumed bandwidth
 * allows.
 * allows and link asymmetric preference is ignored (if @keep_asym is %false).
 */
static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
			    struct tb_port *dst_port, int requested_up,
			    int requested_down)
			    int requested_down, bool keep_asym)
{
	bool clx = false, clx_disabled = false, downstream;
	struct tb_switch *sw;
	bool clx, downstream;
	struct tb_port *up;
	int ret = 0;

	if (!asym_threshold)
		return 0;

	/* Disable CL states before doing any transitions */
	downstream = tb_port_path_direction_downstream(src_port, dst_port);
	/* Pick up router deepest in the hierarchy */
	if (downstream)
@@ -1199,8 +1208,6 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
	else
		sw = src_port->sw;

	clx = tb_disable_clx(sw);

	tb_for_each_upstream_port_on_path(src_port, dst_port, up) {
		int consumed_up, consumed_down;

@@ -1233,6 +1240,25 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
		if (up->sw->link_width == TB_LINK_WIDTH_DUAL)
			continue;

		/*
		 * Here consumed < threshold so we can transition the
		 * link to symmetric.
		 *
		 * However, if the router prefers asymmetric link we
		 * honor that (unless @keep_asym is %false).
		 */
		if (keep_asym &&
		    up->sw->preferred_link_width > TB_LINK_WIDTH_DUAL) {
			tb_sw_dbg(up->sw, "keeping preferred asymmetric link\n");
			continue;
		}

		/* Disable CL states before doing any transitions */
		if (!clx_disabled) {
			clx = tb_disable_clx(sw);
			clx_disabled = true;
		}

		tb_sw_dbg(up->sw, "configuring symmetric link\n");

		ret = tb_switch_set_link_width(up->sw, TB_LINK_WIDTH_DUAL);
@@ -1280,7 +1306,7 @@ static void tb_configure_link(struct tb_port *down, struct tb_port *up,
		struct tb_port *host_port;

		host_port = tb_port_at(tb_route(sw), tb->root_switch);
		tb_configure_sym(tb, host_port, up, 0, 0);
		tb_configure_sym(tb, host_port, up, 0, 0, false);
	}

	/* Set the link configured */
@@ -1465,7 +1491,7 @@ static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
		 * If bandwidth on a link is < asym_threshold
		 * transition the link to symmetric.
		 */
		tb_configure_sym(tb, src_port, dst_port, 0, 0);
		tb_configure_sym(tb, src_port, dst_port, 0, 0, true);
		/* Now we can allow the domain to runtime suspend again */
		pm_runtime_mark_last_busy(&dst_port->sw->dev);
		pm_runtime_put_autosuspend(&dst_port->sw->dev);
@@ -1901,7 +1927,7 @@ static void tb_dp_resource_available(struct tb *tb, struct tb_port *port)
			return;
	}

	tb_port_dbg(port, "DP %s resource available\n",
	tb_port_dbg(port, "DP %s resource available after hotplug\n",
		    tb_port_is_dpin(port) ? "IN" : "OUT");
	list_add_tail(&port->list, &tcm->dp_resources);

@@ -2287,7 +2313,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
		 * If bandwidth on a link is < asym_threshold transition
		 * the link to symmetric.
		 */
		tb_configure_sym(tb, in, out, *requested_up, *requested_down);
		tb_configure_sym(tb, in, out, *requested_up, *requested_down, true);
		/*
		 * If requested bandwidth is less or equal than what is
		 * currently allocated to that tunnel we simply change
@@ -2330,7 +2356,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
		ret = tb_configure_asym(tb, in, out, *requested_up,
					*requested_down);
		if (ret) {
			tb_configure_sym(tb, in, out, 0, 0);
			tb_configure_sym(tb, in, out, 0, 0, true);
			return ret;
		}

@@ -2338,7 +2364,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
						requested_down);
		if (ret) {
			tb_tunnel_warn(tunnel, "failed to allocate bandwidth\n");
			tb_configure_sym(tb, in, out, 0, 0);
			tb_configure_sym(tb, in, out, 0, 0, true);
		}
	} else {
		ret = -ENOBUFS;
Loading