Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Thunderbolt driver - path/tunnel functionality
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Copyright (C) 2019, Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/ktime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include "tb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) static void tb_dump_hop(const struct tb_path_hop *hop, const struct tb_regs_hop *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 	const struct tb_port *port = hop->in_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	tb_port_dbg(port, " In HopID: %d => Out port: %d Out HopID: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 		    hop->in_hop_index, regs->out_port, regs->next_hop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	tb_port_dbg(port, "  Weight: %d Priority: %d Credits: %d Drop: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 		    regs->weight, regs->priority,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 		    regs->initial_credits, regs->drop_packages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	tb_port_dbg(port, "   Counter enabled: %d Counter index: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 		    regs->counter_enable, regs->counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	tb_port_dbg(port, "  Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 		    regs->ingress_fc, regs->egress_fc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 		    regs->ingress_shared_buffer, regs->egress_shared_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	tb_port_dbg(port, "  Unknown1: %#x Unknown2: %#x Unknown3: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 		    regs->unknown1, regs->unknown2, regs->unknown3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) static struct tb_port *tb_path_find_dst_port(struct tb_port *src, int src_hopid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 					     int dst_hopid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	struct tb_port *port, *out_port = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	struct tb_regs_hop hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct tb_switch *sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	int i, ret, hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	hopid = src_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	port = src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	for (i = 0; port && i < TB_PATH_MAX_HOPS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 		sw = port->sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 		ret = tb_port_read(port, &hop, TB_CFG_HOPS, 2 * hopid, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 			tb_port_warn(port, "failed to read path at %d\n", hopid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 			return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 		if (!hop.enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 			return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		out_port = &sw->ports[hop.out_port];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		hopid = hop.next_hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		port = out_port->remote;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	return out_port && hopid == dst_hopid ? out_port : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) static int tb_path_find_src_hopid(struct tb_port *src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	const struct tb_port *dst, int dst_hopid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	struct tb_port *out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	for (i = TB_PATH_MIN_HOPID; i <= src->config.max_in_hop_id; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		out = tb_path_find_dst_port(src, i, dst_hopid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		if (out == dst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 			return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81)  * tb_path_discover() - Discover a path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82)  * @src: First input port of a path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83)  * @src_hopid: Starting HopID of a path (%-1 if don't care)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84)  * @dst: Expected destination port of the path (%NULL if don't care)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)  * @dst_hopid: HopID to the @dst (%-1 if don't care)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)  * @last: Last port is filled here if not %NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87)  * @name: Name of the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89)  * Follows a path starting from @src and @src_hopid to the last output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)  * port of the path. Allocates HopIDs for the visited ports. Call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91)  * tb_path_free() to release the path and allocated HopIDs when the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)  * is not needed anymore.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)  * Note function discovers also incomplete paths so caller should check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)  * that the @dst port is the expected one. If it is not, the path can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96)  * cleaned up by calling tb_path_deactivate() before tb_path_free().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98)  * Return: Discovered path on success, %NULL in case of failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 				 struct tb_port *dst, int dst_hopid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 				 struct tb_port **last, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	struct tb_port *out_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	struct tb_regs_hop hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	struct tb_path *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	struct tb_switch *sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	struct tb_port *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	size_t num_hops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	int ret, i, h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	if (src_hopid < 0 && dst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		 * For incomplete paths the intermediate HopID can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		 * different from the one used by the protocol adapter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		 * so in that case find a path that ends on @dst with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		 * matching @dst_hopid. That should give us the correct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		 * HopID for the @src.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		src_hopid = tb_path_find_src_hopid(src, dst, dst_hopid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		if (!src_hopid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 			return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	p = src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	h = src_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	num_hops = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	for (i = 0; p && i < TB_PATH_MAX_HOPS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		sw = p->sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		ret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 			tb_port_warn(p, "failed to read path at %d\n", h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		/* If the hop is not enabled we got an incomplete path */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		if (!hop.enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		out_port = &sw->ports[hop.out_port];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		if (last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 			*last = out_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		h = hop.next_hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		p = out_port->remote;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		num_hops++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	path = kzalloc(sizeof(*path), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	if (!path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	path->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	path->tb = src->sw->tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	path->path_length = num_hops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	path->activated = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	if (!path->hops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		kfree(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	p = src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	h = src_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	for (i = 0; i < num_hops; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		int next_hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		sw = p->sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		ret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			tb_port_warn(p, "failed to read path at %d\n", h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		if (tb_port_alloc_in_hopid(p, h, h) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		out_port = &sw->ports[hop.out_port];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		next_hop = hop.next_hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		if (tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 			tb_port_release_in_hopid(p, h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		path->hops[i].in_port = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		path->hops[i].in_hop_index = h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 		path->hops[i].in_counter_index = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		path->hops[i].out_port = out_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		path->hops[i].next_hop_index = next_hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		h = next_hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		p = out_port->remote;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	return path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	tb_port_warn(src, "failed to discover path starting at HopID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		     src_hopid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	tb_path_free(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)  * tb_path_alloc() - allocate a thunderbolt path between two ports
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)  * @tb: Domain pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)  * @src: Source port of the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)  * @src_hopid: HopID used for the first ingress port in the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)  * @dst: Destination port of the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)  * @dst_hopid: HopID used for the last egress port in the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)  * @link_nr: Preferred link if there are dual links on the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)  * @name: Name of the path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)  * Creates path between two ports starting with given @src_hopid. Reserves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)  * HopIDs for each port (they can be different from @src_hopid depending on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)  * how many HopIDs each port already have reserved). If there are dual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)  * links on the path, prioritizes using @link_nr but takes into account
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)  * that the lanes may be bonded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)  * Return: Returns a tb_path on success or NULL on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			      struct tb_port *dst, int dst_hopid, int link_nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 			      const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	struct tb_port *in_port, *out_port, *first_port, *last_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	int in_hopid, out_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	struct tb_path *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	size_t num_hops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	path = kzalloc(sizeof(*path), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	if (!path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	first_port = last_port = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	tb_for_each_port_on_path(src, dst, in_port) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		if (!first_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			first_port = in_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 		last_port = in_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	/* Check that src and dst are reachable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	if (first_port != src || last_port != dst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		kfree(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	/* Each hop takes two ports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	num_hops = i / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	if (!path->hops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		kfree(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	in_hopid = src_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	out_port = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	for (i = 0; i < num_hops; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		in_port = tb_next_port_on_path(src, dst, out_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 		if (!in_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		/* When lanes are bonded primary link must be used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 		if (!in_port->bonded && in_port->dual_link_port &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 		    in_port->link_nr != link_nr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 			in_port = in_port->dual_link_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		ret = tb_port_alloc_in_hopid(in_port, in_hopid, in_hopid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		in_hopid = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		out_port = tb_next_port_on_path(src, dst, in_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		if (!out_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		 * Pick up right port when going from non-bonded to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		 * bonded or from bonded to non-bonded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 		if (out_port->dual_link_port) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			if (!in_port->bonded && out_port->bonded &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 			    out_port->link_nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 				/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 				 * Use primary link when going from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 				 * non-bonded to bonded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 				out_port = out_port->dual_link_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 			} else if (!out_port->bonded &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 				   out_port->link_nr != link_nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 				/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 				 * If out port is not bonded follow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 				 * link_nr.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 				out_port = out_port->dual_link_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		if (i == num_hops - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 			ret = tb_port_alloc_out_hopid(out_port, dst_hopid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 						      dst_hopid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 			ret = tb_port_alloc_out_hopid(out_port, -1, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 		if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		out_hopid = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 		path->hops[i].in_hop_index = in_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		path->hops[i].in_port = in_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		path->hops[i].in_counter_index = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		path->hops[i].out_port = out_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		path->hops[i].next_hop_index = out_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		in_hopid = out_hopid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	path->tb = tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	path->path_length = num_hops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	path->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	return path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	tb_path_free(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)  * tb_path_free() - free a path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)  * @path: Path to free
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)  * Frees a path. The path does not need to be deactivated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) void tb_path_free(struct tb_path *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	for (i = 0; i < path->path_length; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		const struct tb_path_hop *hop = &path->hops[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		if (hop->in_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 			tb_port_release_in_hopid(hop->in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 						 hop->in_hop_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		if (hop->out_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 			tb_port_release_out_hopid(hop->out_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 						  hop->next_hop_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	kfree(path->hops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	kfree(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static void __tb_path_deallocate_nfc(struct tb_path *path, int first_hop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	int i, res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	for (i = first_hop; i < path->path_length; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		res = tb_port_add_nfc_credits(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 					      -path->nfc_credits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			tb_port_warn(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 				     "nfc credits deallocation failed for hop %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 				     i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 				    bool clear_fc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	struct tb_regs_hop hop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	ktime_t timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	/* Disable the path */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	ret = tb_port_read(port, &hop, TB_CFG_HOPS, 2 * hop_index, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	/* Already disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	if (!hop.enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	hop.enable = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	ret = tb_port_write(port, &hop, TB_CFG_HOPS, 2 * hop_index, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	/* Wait until it is drained */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	timeout = ktime_add_ms(ktime_get(), 500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		ret = tb_port_read(port, &hop, TB_CFG_HOPS, 2 * hop_index, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 		if (!hop.pending) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 			if (clear_fc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 				/* Clear flow control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 				hop.ingress_fc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 				hop.egress_fc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 				hop.ingress_shared_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 				hop.egress_shared_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 				return tb_port_write(port, &hop, TB_CFG_HOPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 						     2 * hop_index, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 		usleep_range(10, 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	} while (ktime_before(ktime_get(), timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) static void __tb_path_deactivate_hops(struct tb_path *path, int first_hop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	int i, res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	for (i = first_hop; i < path->path_length; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 		res = __tb_path_deactivate_hop(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 					       path->hops[i].in_hop_index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 					       path->clear_fc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 		if (res && res != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 			tb_port_warn(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 				     "hop deactivation failed for hop %d, index %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 				     i, path->hops[i].in_hop_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) void tb_path_deactivate(struct tb_path *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	if (!path->activated) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 		tb_WARN(path->tb, "trying to deactivate an inactive path\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	tb_dbg(path->tb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	       "deactivating %s path from %llx:%x to %llx:%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	       path->name, tb_route(path->hops[0].in_port->sw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	       path->hops[0].in_port->port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	       tb_route(path->hops[path->path_length - 1].out_port->sw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	       path->hops[path->path_length - 1].out_port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	__tb_path_deactivate_hops(path, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	__tb_path_deallocate_nfc(path, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	path->activated = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)  * tb_path_activate() - activate a path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)  * Activate a path starting with the last hop and iterating backwards. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)  * caller must fill path->hops before calling tb_path_activate().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)  * Return: Returns 0 on success or an error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int tb_path_activate(struct tb_path *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	int i, res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	enum tb_path_port out_mask, in_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	if (path->activated) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		tb_WARN(path->tb, "trying to activate already activated path\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	tb_dbg(path->tb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	       "activating %s path from %llx:%x to %llx:%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	       path->name, tb_route(path->hops[0].in_port->sw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	       path->hops[0].in_port->port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	       tb_route(path->hops[path->path_length - 1].out_port->sw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	       path->hops[path->path_length - 1].out_port->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	/* Clear counters. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	for (i = path->path_length - 1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 		if (path->hops[i].in_counter_index == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 		res = tb_port_clear_counter(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 					    path->hops[i].in_counter_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 		if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	/* Add non flow controlled credits. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 	for (i = path->path_length - 1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 		res = tb_port_add_nfc_credits(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 					      path->nfc_credits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 		if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 			__tb_path_deallocate_nfc(path, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	/* Activate hops. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	for (i = path->path_length - 1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 		struct tb_regs_hop hop = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 		/* If it is left active deactivate it first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 		__tb_path_deactivate_hop(path->hops[i].in_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 				path->hops[i].in_hop_index, path->clear_fc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 		/* dword 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 		hop.next_hop = path->hops[i].next_hop_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 		hop.out_port = path->hops[i].out_port->port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 		hop.initial_credits = path->hops[i].initial_credits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 		hop.unknown1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 		hop.enable = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 		/* dword 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 		out_mask = (i == path->path_length - 1) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 				TB_PATH_DESTINATION : TB_PATH_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 		in_mask = (i == 0) ? TB_PATH_SOURCE : TB_PATH_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 		hop.weight = path->weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 		hop.unknown2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 		hop.priority = path->priority;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 		hop.drop_packages = path->drop_packages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 		hop.counter = path->hops[i].in_counter_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 		hop.counter_enable = path->hops[i].in_counter_index != -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 		hop.ingress_fc = path->ingress_fc_enable & in_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 		hop.egress_fc = path->egress_fc_enable & out_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 		hop.ingress_shared_buffer = path->ingress_shared_buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 					    & in_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 		hop.egress_shared_buffer = path->egress_shared_buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 					    & out_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		hop.unknown3 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 		tb_port_dbg(path->hops[i].in_port, "Writing hop %d\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 		tb_dump_hop(&path->hops[i], &hop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 		res = tb_port_write(path->hops[i].in_port, &hop, TB_CFG_HOPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 				    2 * path->hops[i].in_hop_index, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 		if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 			__tb_path_deactivate_hops(path, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 			__tb_path_deallocate_nfc(path, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 			goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	path->activated = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	tb_dbg(path->tb, "path activation complete\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 	tb_WARN(path->tb, "path activation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)  * tb_path_is_invalid() - check whether any ports on the path are invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)  * Return: Returns true if the path is invalid, false otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) bool tb_path_is_invalid(struct tb_path *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	for (i = 0; i < path->path_length; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 		if (path->hops[i].in_port->sw->is_unplugged)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 			return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 		if (path->hops[i].out_port->sw->is_unplugged)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 			return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)  * tb_path_port_on_path() - Does the path go through certain port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)  * @path: Path to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)  * @port: Switch to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)  * Goes over all hops on path and checks if @port is any of them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)  * Direction does not matter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) bool tb_path_port_on_path(const struct tb_path *path, const struct tb_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	for (i = 0; i < path->path_length; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 		if (path->hops[i].in_port == port ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 		    path->hops[i].out_port == port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 			return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }