drivers/thunderbolt/path.c

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

File Facts

System
Linux kernel
Corpus path
drivers/thunderbolt/path.c
Extension
.c
Size
16124 bytes
Lines
619
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

if (ret) {
			tb_port_warn(port, "failed to read path at %d\n", hopid);
			return NULL;
		}

		if (!hop.enable)
			return NULL;

		out_port = &sw->ports[hop.out_port];
		hopid = hop.next_hop;
		port = out_port->remote;
	}

	return out_port && hopid == dst_hopid ? out_port : NULL;
}

static int tb_path_find_src_hopid(struct tb_port *src,
	const struct tb_port *dst, int dst_hopid)
{
	struct tb_port *out;
	int i;

	for (i = TB_PATH_MIN_HOPID; i <= src->config.max_in_hop_id; i++) {
		out = tb_path_find_dst_port(src, i, dst_hopid);
		if (out == dst)
			return i;
	}

	return 0;
}

/**
 * tb_path_discover() - Discover a path
 * @src: First input port of a path
 * @src_hopid: Starting HopID of a path (%-1 if don't care)
 * @dst: Expected destination port of the path (%NULL if don't care)
 * @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 (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
 * cleaned up by calling tb_path_deactivate() before tb_path_free().
 *
 * Return: Pointer to &struct tb_path, %NULL in case of failure.
 */
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,
				 bool alloc_hopid)
{
	struct tb_port *out_port;
	struct tb_regs_hop hop;
	struct tb_path *path;
	struct tb_switch *sw;
	struct tb_port *p;
	size_t num_hops;
	int ret, i, h;

	if (src_hopid < 0 && dst) {
		/*
		 * For incomplete paths the intermediate HopID can be
		 * different from the one used by the protocol adapter
		 * so in that case find a path that ends on @dst with
		 * matching @dst_hopid. That should give us the correct
		 * HopID for the @src.
		 */
		src_hopid = tb_path_find_src_hopid(src, dst, dst_hopid);
		if (!src_hopid)
			return NULL;
	}

	p = src;
	h = src_hopid;
	num_hops = 0;

	for (i = 0; p && i < TB_PATH_MAX_HOPS; i++) {
		sw = p->sw;

		ret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);
		if (ret) {
			tb_port_warn(p, "failed to read path at %d\n", h);
			return NULL;
		}

Annotation

Implementation Notes