drivers/thunderbolt/tb.c

Source file repositories/reference/linux-study-clean/drivers/thunderbolt/tb.c

File Facts

System
Linux kernel
Corpus path
drivers/thunderbolt/tb.c
Extension
.c
Size
89563 bytes
Lines
3400
Domain
Driver Families
Bucket
drivers/thunderbolt
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct tb_cm {
	struct list_head tunnel_list;
	struct list_head dp_resources;
	bool hotplug_active;
	struct delayed_work remove_work;
	struct tb_bandwidth_group groups[MAX_GROUPS];
};

static inline struct tb *tcm_to_tb(struct tb_cm *tcm)
{
	return ((void *)tcm - sizeof(struct tb));
}

struct tb_hotplug_event {
	struct delayed_work work;
	struct tb *tb;
	u64 route;
	u8 port;
	bool unplug;
	int retry;
};

static void tb_scan_port(struct tb_port *port);
static void tb_handle_hotplug(struct work_struct *work);
static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port,
				       const char *reason);
static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port,
					  int retry, unsigned long delay);

static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug)
{
	struct tb_hotplug_event *ev;

	ev = kmalloc_obj(*ev);
	if (!ev)
		return;

	ev->tb = tb;
	ev->route = route;
	ev->port = port;
	ev->unplug = unplug;
	INIT_DELAYED_WORK(&ev->work, tb_handle_hotplug);
	queue_delayed_work(tb->wq, &ev->work, 0);
}

/* enumeration & hot plug handling */

static void tb_add_dp_resources(struct tb_switch *sw)
{
	struct tb_cm *tcm = tb_priv(sw->tb);
	struct tb_port *port;

	tb_switch_for_each_port(sw, port) {
		if (!tb_port_is_dpin(port))
			continue;

		if (!tb_switch_query_dp_resource(sw, port))
			continue;

		/*
		 * If DP IN on device router exist, position it at the
		 * beginning of the DP resources list, so that it is used
		 * before DP IN of the host router. This way external GPU(s)
		 * will be prioritized when pairing DP IN to a DP OUT.
		 */
		if (tb_route(sw))
			list_add(&port->list, &tcm->dp_resources);
		else
			list_add_tail(&port->list, &tcm->dp_resources);

		tb_port_dbg(port, "DP IN resource available\n");
	}
}

static void tb_remove_dp_resources(struct tb_switch *sw)
{
	struct tb_cm *tcm = tb_priv(sw->tb);
	struct tb_port *port, *tmp;

	/* Clear children resources first */
	tb_switch_for_each_port(sw, port) {
		if (tb_port_has_remote(port))
			tb_remove_dp_resources(port->remote->sw);
	}

	list_for_each_entry_safe(port, tmp, &tcm->dp_resources, list) {
		if (port->sw == sw) {
			tb_port_dbg(port, "DP OUT resource unavailable\n");
			list_del_init(&port->list);
		}

Annotation

Implementation Notes