Commit cae5f515 authored by Mika Westerberg's avatar Mika Westerberg
Browse files

thunderbolt: Add USB4 port devices



Create devices for each USB4 port. This is needed when we add retimer
access when there is no device connected but may be useful for other
purposes too following what USB subsystem does. This exports a single
attribute "link" that shows the type of the USB4 link (or "none" if
there is no cable connected).

Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0f28879c
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -290,6 +290,13 @@ Contact: thunderbolt-software@lists.01.org
Description:	This contains XDomain service specific settings as
		bitmask. Format: %x

What:		/sys/bus/thunderbolt/devices/usb4_portX/link
Date:		Sep 2021
KernelVersion:	v5.14
Contact:	Mika Westerberg <mika.westerberg@linux.intel.com>
Description:	Returns the current link mode. Possible values are
		"usb4", "tbt" and "none".

What:		/sys/bus/thunderbolt/devices/<device>:<port>.<index>/device
Date:		Oct 2020
KernelVersion:	v5.9
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
obj-${CONFIG_USB4} := thunderbolt.o
thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o
thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o
thunderbolt-objs += nvm.o retimer.o quirks.o
thunderbolt-objs += usb4_port.o nvm.o retimer.o quirks.o

thunderbolt-${CONFIG_ACPI} += acpi.o
thunderbolt-$(CONFIG_DEBUG_FS) += debugfs.o
+10 −5
Original line number Diff line number Diff line
@@ -283,11 +283,13 @@ 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;

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

	ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor,
@@ -331,7 +333,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 = &port->sw->dev;
	rt->dev.parent = &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),
@@ -389,7 +391,7 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
	struct tb_retimer_lookup lookup = { .port = port, .index = index };
	struct device *dev;

	dev = device_find_child(&port->sw->dev, &lookup, retimer_match);
	dev = device_find_child(&port->usb4->dev, &lookup, retimer_match);
	if (dev)
		return tb_to_retimer(dev);

@@ -479,7 +481,10 @@ static int remove_retimer(struct device *dev, void *data)
 */
void tb_retimer_remove_all(struct tb_port *port)
{
	if (port->cap_usb4)
		device_for_each_child_reverse(&port->sw->dev, port,
	struct usb4_port *usb4;

	usb4 = port->usb4;
	if (usb4)
		device_for_each_child_reverse(&usb4->dev, port,
					      remove_retimer);
}
+15 −2
Original line number Diff line number Diff line
@@ -2741,11 +2741,16 @@ int tb_switch_add(struct tb_switch *sw)
				 sw->device_name);
	}

	ret = usb4_switch_add_ports(sw);
	if (ret) {
		dev_err(&sw->dev, "failed to add USB4 ports\n");
		goto err_del;
	}

	ret = tb_switch_nvm_add(sw);
	if (ret) {
		dev_err(&sw->dev, "failed to add NVM devices\n");
		device_del(&sw->dev);
		return ret;
		goto err_ports;
	}

	/*
@@ -2766,6 +2771,13 @@ int tb_switch_add(struct tb_switch *sw)

	tb_switch_debugfs_init(sw);
	return 0;

err_ports:
	usb4_switch_remove_ports(sw);
err_del:
	device_del(&sw->dev);

	return ret;
}

/**
@@ -2805,6 +2817,7 @@ void tb_switch_remove(struct tb_switch *sw)
		tb_plug_events_active(sw, false);

	tb_switch_nvm_remove(sw);
	usb4_switch_remove_ports(sw);

	if (tb_route(sw))
		dev_info(&sw->dev, "device disconnected\n");
+30 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ struct tb_switch {
 * @cap_tmu: Offset of the adapter specific TMU capability (%0 if not present)
 * @cap_adap: Offset of the adapter specific capability (%0 if not present)
 * @cap_usb4: Offset to the USB4 port capability (%0 if not present)
 * @usb4: Pointer to the USB4 port structure (only if @cap_usb4 is != %0)
 * @port: Port number on switch
 * @disabled: Disabled by eeprom or enabled but not implemented
 * @bonded: true if the port is bonded (two lanes combined as one)
@@ -228,6 +229,7 @@ struct tb_port {
	int cap_tmu;
	int cap_adap;
	int cap_usb4;
	struct usb4_port *usb4;
	u8 port;
	bool disabled;
	bool bonded;
@@ -241,6 +243,16 @@ struct tb_port {
	unsigned int dma_credits;
};

/**
 * struct usb4_port - USB4 port device
 * @dev: Device for the port
 * @port: Pointer to the lane 0 adapter
 */
struct usb4_port {
	struct device dev;
	struct tb_port *port;
};

/**
 * tb_retimer: Thunderbolt retimer
 * @dev: Device for the retimer
@@ -645,6 +657,7 @@ struct tb *tb_probe(struct tb_nhi *nhi);
extern struct device_type tb_domain_type;
extern struct device_type tb_retimer_type;
extern struct device_type tb_switch_type;
extern struct device_type usb4_port_device_type;

int tb_domain_init(void);
void tb_domain_exit(void);
@@ -1038,6 +1051,8 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
					  const struct tb_port *port);
struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw,
					  const struct tb_port *port);
int usb4_switch_add_ports(struct tb_switch *sw);
void usb4_switch_remove_ports(struct tb_switch *sw);

int usb4_port_unlock(struct tb_port *port);
int usb4_port_configure(struct tb_port *port);
@@ -1070,6 +1085,21 @@ int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw,
int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw,
				     int *downstream_bw);

static inline bool tb_is_usb4_port_device(const struct device *dev)
{
	return dev->type == &usb4_port_device_type;
}

static inline struct usb4_port *tb_to_usb4_port_device(struct device *dev)
{
	if (tb_is_usb4_port_device(dev))
		return container_of(dev, struct usb4_port, dev);
	return NULL;
}

struct usb4_port *usb4_port_device_add(struct tb_port *port);
void usb4_port_device_remove(struct usb4_port *usb4);

/* Keep link controller awake during update */
#define QUIRK_FORCE_POWER_LINK_CONTROLLER		BIT(0)

Loading