xref: /openbmc/linux/drivers/thunderbolt/tb.c (revision 4f807e47)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2d6cc51cdSAndreas Noever /*
399cabbb0SMika Westerberg  * Thunderbolt driver - bus logic (NHI independent)
4d6cc51cdSAndreas Noever  *
5d6cc51cdSAndreas Noever  * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
699cabbb0SMika Westerberg  * Copyright (C) 2019, Intel Corporation
7d6cc51cdSAndreas Noever  */
8d6cc51cdSAndreas Noever 
9d6cc51cdSAndreas Noever #include <linux/slab.h>
10d6cc51cdSAndreas Noever #include <linux/errno.h>
11d6cc51cdSAndreas Noever #include <linux/delay.h>
12630b3affSLukas Wunner #include <linux/platform_data/x86/apple.h>
13d6cc51cdSAndreas Noever 
14d6cc51cdSAndreas Noever #include "tb.h"
157adf6097SAndreas Noever #include "tb_regs.h"
161752b9f7SMika Westerberg #include "tunnel.h"
17d6cc51cdSAndreas Noever 
189d3cce0bSMika Westerberg /**
199d3cce0bSMika Westerberg  * struct tb_cm - Simple Thunderbolt connection manager
209d3cce0bSMika Westerberg  * @tunnel_list: List of active tunnels
219d3cce0bSMika Westerberg  * @hotplug_active: tb_handle_hotplug will stop progressing plug
229d3cce0bSMika Westerberg  *		    events and exit if this is not set (it needs to
239d3cce0bSMika Westerberg  *		    acquire the lock one more time). Used to drain wq
249d3cce0bSMika Westerberg  *		    after cfg has been paused.
259d3cce0bSMika Westerberg  */
269d3cce0bSMika Westerberg struct tb_cm {
279d3cce0bSMika Westerberg 	struct list_head tunnel_list;
289d3cce0bSMika Westerberg 	bool hotplug_active;
299d3cce0bSMika Westerberg };
309da672a4SAndreas Noever 
314f807e47SMika Westerberg struct tb_hotplug_event {
324f807e47SMika Westerberg 	struct work_struct work;
334f807e47SMika Westerberg 	struct tb *tb;
344f807e47SMika Westerberg 	u64 route;
354f807e47SMika Westerberg 	u8 port;
364f807e47SMika Westerberg 	bool unplug;
374f807e47SMika Westerberg };
384f807e47SMika Westerberg 
394f807e47SMika Westerberg static void tb_handle_hotplug(struct work_struct *work);
404f807e47SMika Westerberg 
414f807e47SMika Westerberg static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug)
424f807e47SMika Westerberg {
434f807e47SMika Westerberg 	struct tb_hotplug_event *ev;
444f807e47SMika Westerberg 
454f807e47SMika Westerberg 	ev = kmalloc(sizeof(*ev), GFP_KERNEL);
464f807e47SMika Westerberg 	if (!ev)
474f807e47SMika Westerberg 		return;
484f807e47SMika Westerberg 
494f807e47SMika Westerberg 	ev->tb = tb;
504f807e47SMika Westerberg 	ev->route = route;
514f807e47SMika Westerberg 	ev->port = port;
524f807e47SMika Westerberg 	ev->unplug = unplug;
534f807e47SMika Westerberg 	INIT_WORK(&ev->work, tb_handle_hotplug);
544f807e47SMika Westerberg 	queue_work(tb->wq, &ev->work);
554f807e47SMika Westerberg }
564f807e47SMika Westerberg 
579da672a4SAndreas Noever /* enumeration & hot plug handling */
589da672a4SAndreas Noever 
590414bec5SMika Westerberg static void tb_discover_tunnels(struct tb_switch *sw)
600414bec5SMika Westerberg {
610414bec5SMika Westerberg 	struct tb *tb = sw->tb;
620414bec5SMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
630414bec5SMika Westerberg 	struct tb_port *port;
640414bec5SMika Westerberg 	int i;
650414bec5SMika Westerberg 
660414bec5SMika Westerberg 	for (i = 1; i <= sw->config.max_port_number; i++) {
670414bec5SMika Westerberg 		struct tb_tunnel *tunnel = NULL;
680414bec5SMika Westerberg 
690414bec5SMika Westerberg 		port = &sw->ports[i];
700414bec5SMika Westerberg 		switch (port->config.type) {
714f807e47SMika Westerberg 		case TB_TYPE_DP_HDMI_IN:
724f807e47SMika Westerberg 			tunnel = tb_tunnel_discover_dp(tb, port);
734f807e47SMika Westerberg 			break;
744f807e47SMika Westerberg 
750414bec5SMika Westerberg 		case TB_TYPE_PCIE_DOWN:
760414bec5SMika Westerberg 			tunnel = tb_tunnel_discover_pci(tb, port);
770414bec5SMika Westerberg 			break;
780414bec5SMika Westerberg 
790414bec5SMika Westerberg 		default:
800414bec5SMika Westerberg 			break;
810414bec5SMika Westerberg 		}
820414bec5SMika Westerberg 
834f807e47SMika Westerberg 		if (!tunnel)
844f807e47SMika Westerberg 			continue;
854f807e47SMika Westerberg 
864f807e47SMika Westerberg 		if (tb_tunnel_is_pci(tunnel)) {
870414bec5SMika Westerberg 			struct tb_switch *parent = tunnel->dst_port->sw;
880414bec5SMika Westerberg 
890414bec5SMika Westerberg 			while (parent != tunnel->src_port->sw) {
900414bec5SMika Westerberg 				parent->boot = true;
910414bec5SMika Westerberg 				parent = tb_switch_parent(parent);
920414bec5SMika Westerberg 			}
934f807e47SMika Westerberg 		}
940414bec5SMika Westerberg 
950414bec5SMika Westerberg 		list_add_tail(&tunnel->list, &tcm->tunnel_list);
960414bec5SMika Westerberg 	}
970414bec5SMika Westerberg 
980414bec5SMika Westerberg 	for (i = 1; i <= sw->config.max_port_number; i++) {
990414bec5SMika Westerberg 		if (tb_port_has_remote(&sw->ports[i]))
1000414bec5SMika Westerberg 			tb_discover_tunnels(sw->ports[i].remote->sw);
1010414bec5SMika Westerberg 	}
1020414bec5SMika Westerberg }
1039da672a4SAndreas Noever 
1049da672a4SAndreas Noever static void tb_scan_port(struct tb_port *port);
1059da672a4SAndreas Noever 
1069da672a4SAndreas Noever /**
1079da672a4SAndreas Noever  * tb_scan_switch() - scan for and initialize downstream switches
1089da672a4SAndreas Noever  */
1099da672a4SAndreas Noever static void tb_scan_switch(struct tb_switch *sw)
1109da672a4SAndreas Noever {
1119da672a4SAndreas Noever 	int i;
1129da672a4SAndreas Noever 	for (i = 1; i <= sw->config.max_port_number; i++)
1139da672a4SAndreas Noever 		tb_scan_port(&sw->ports[i]);
1149da672a4SAndreas Noever }
1159da672a4SAndreas Noever 
1169da672a4SAndreas Noever /**
1179da672a4SAndreas Noever  * tb_scan_port() - check for and initialize switches below port
1189da672a4SAndreas Noever  */
1199da672a4SAndreas Noever static void tb_scan_port(struct tb_port *port)
1209da672a4SAndreas Noever {
12199cabbb0SMika Westerberg 	struct tb_cm *tcm = tb_priv(port->sw->tb);
122dfe40ca4SMika Westerberg 	struct tb_port *upstream_port;
1239da672a4SAndreas Noever 	struct tb_switch *sw;
124dfe40ca4SMika Westerberg 
1259da672a4SAndreas Noever 	if (tb_is_upstream_port(port))
1269da672a4SAndreas Noever 		return;
1274f807e47SMika Westerberg 
1284f807e47SMika Westerberg 	if (tb_port_is_dpout(port) && tb_dp_port_hpd_is_active(port) == 1 &&
1294f807e47SMika Westerberg 	    !tb_dp_port_is_enabled(port)) {
1304f807e47SMika Westerberg 		tb_port_dbg(port, "DP adapter HPD set, queuing hotplug\n");
1314f807e47SMika Westerberg 		tb_queue_hotplug(port->sw->tb, tb_route(port->sw), port->port,
1324f807e47SMika Westerberg 				 false);
1334f807e47SMika Westerberg 		return;
1344f807e47SMika Westerberg 	}
1354f807e47SMika Westerberg 
1369da672a4SAndreas Noever 	if (port->config.type != TB_TYPE_PORT)
1379da672a4SAndreas Noever 		return;
138343fcb8cSAndreas Noever 	if (port->dual_link_port && port->link_nr)
139343fcb8cSAndreas Noever 		return; /*
140343fcb8cSAndreas Noever 			 * Downstream switch is reachable through two ports.
141343fcb8cSAndreas Noever 			 * Only scan on the primary port (link_nr == 0).
142343fcb8cSAndreas Noever 			 */
1439da672a4SAndreas Noever 	if (tb_wait_for_port(port, false) <= 0)
1449da672a4SAndreas Noever 		return;
1459da672a4SAndreas Noever 	if (port->remote) {
1469da672a4SAndreas Noever 		tb_port_WARN(port, "port already has a remote!\n");
1479da672a4SAndreas Noever 		return;
1489da672a4SAndreas Noever 	}
149bfe778acSMika Westerberg 	sw = tb_switch_alloc(port->sw->tb, &port->sw->dev,
150bfe778acSMika Westerberg 			     tb_downstream_route(port));
1519da672a4SAndreas Noever 	if (!sw)
1529da672a4SAndreas Noever 		return;
153bfe778acSMika Westerberg 
154bfe778acSMika Westerberg 	if (tb_switch_configure(sw)) {
155bfe778acSMika Westerberg 		tb_switch_put(sw);
156bfe778acSMika Westerberg 		return;
157bfe778acSMika Westerberg 	}
158bfe778acSMika Westerberg 
15999cabbb0SMika Westerberg 	/*
16099cabbb0SMika Westerberg 	 * Do not send uevents until we have discovered all existing
16199cabbb0SMika Westerberg 	 * tunnels and know which switches were authorized already by
16299cabbb0SMika Westerberg 	 * the boot firmware.
16399cabbb0SMika Westerberg 	 */
16499cabbb0SMika Westerberg 	if (!tcm->hotplug_active)
16599cabbb0SMika Westerberg 		dev_set_uevent_suppress(&sw->dev, true);
166f67cf491SMika Westerberg 
167bfe778acSMika Westerberg 	if (tb_switch_add(sw)) {
168bfe778acSMika Westerberg 		tb_switch_put(sw);
169bfe778acSMika Westerberg 		return;
170bfe778acSMika Westerberg 	}
171bfe778acSMika Westerberg 
172dfe40ca4SMika Westerberg 	/* Link the switches using both links if available */
173dfe40ca4SMika Westerberg 	upstream_port = tb_upstream_port(sw);
174dfe40ca4SMika Westerberg 	port->remote = upstream_port;
175dfe40ca4SMika Westerberg 	upstream_port->remote = port;
176dfe40ca4SMika Westerberg 	if (port->dual_link_port && upstream_port->dual_link_port) {
177dfe40ca4SMika Westerberg 		port->dual_link_port->remote = upstream_port->dual_link_port;
178dfe40ca4SMika Westerberg 		upstream_port->dual_link_port->remote = port->dual_link_port;
179dfe40ca4SMika Westerberg 	}
180dfe40ca4SMika Westerberg 
1819da672a4SAndreas Noever 	tb_scan_switch(sw);
1829da672a4SAndreas Noever }
1839da672a4SAndreas Noever 
1844f807e47SMika Westerberg static int tb_free_tunnel(struct tb *tb, enum tb_tunnel_type type,
1854f807e47SMika Westerberg 			  struct tb_port *src_port, struct tb_port *dst_port)
1864f807e47SMika Westerberg {
1874f807e47SMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
1884f807e47SMika Westerberg 	struct tb_tunnel *tunnel;
1894f807e47SMika Westerberg 
1904f807e47SMika Westerberg 	list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
1914f807e47SMika Westerberg 		if (tunnel->type == type &&
1924f807e47SMika Westerberg 		    ((src_port && src_port == tunnel->src_port) ||
1934f807e47SMika Westerberg 		     (dst_port && dst_port == tunnel->dst_port))) {
1944f807e47SMika Westerberg 			tb_tunnel_deactivate(tunnel);
1954f807e47SMika Westerberg 			list_del(&tunnel->list);
1964f807e47SMika Westerberg 			tb_tunnel_free(tunnel);
1974f807e47SMika Westerberg 			return 0;
1984f807e47SMika Westerberg 		}
1994f807e47SMika Westerberg 	}
2004f807e47SMika Westerberg 
2014f807e47SMika Westerberg 	return -ENODEV;
2024f807e47SMika Westerberg }
2034f807e47SMika Westerberg 
2043364f0c1SAndreas Noever /**
2053364f0c1SAndreas Noever  * tb_free_invalid_tunnels() - destroy tunnels of devices that have gone away
2063364f0c1SAndreas Noever  */
2073364f0c1SAndreas Noever static void tb_free_invalid_tunnels(struct tb *tb)
2083364f0c1SAndreas Noever {
2099d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
21093f36adeSMika Westerberg 	struct tb_tunnel *tunnel;
21193f36adeSMika Westerberg 	struct tb_tunnel *n;
2129d3cce0bSMika Westerberg 
2139d3cce0bSMika Westerberg 	list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
21493f36adeSMika Westerberg 		if (tb_tunnel_is_invalid(tunnel)) {
21593f36adeSMika Westerberg 			tb_tunnel_deactivate(tunnel);
2169d3cce0bSMika Westerberg 			list_del(&tunnel->list);
21793f36adeSMika Westerberg 			tb_tunnel_free(tunnel);
2183364f0c1SAndreas Noever 		}
2193364f0c1SAndreas Noever 	}
2203364f0c1SAndreas Noever }
2213364f0c1SAndreas Noever 
2223364f0c1SAndreas Noever /**
22323dd5bb4SAndreas Noever  * tb_free_unplugged_children() - traverse hierarchy and free unplugged switches
22423dd5bb4SAndreas Noever  */
22523dd5bb4SAndreas Noever static void tb_free_unplugged_children(struct tb_switch *sw)
22623dd5bb4SAndreas Noever {
22723dd5bb4SAndreas Noever 	int i;
22823dd5bb4SAndreas Noever 	for (i = 1; i <= sw->config.max_port_number; i++) {
22923dd5bb4SAndreas Noever 		struct tb_port *port = &sw->ports[i];
230dfe40ca4SMika Westerberg 
231dfe40ca4SMika Westerberg 		if (!tb_port_has_remote(port))
23223dd5bb4SAndreas Noever 			continue;
233dfe40ca4SMika Westerberg 
23423dd5bb4SAndreas Noever 		if (port->remote->sw->is_unplugged) {
235bfe778acSMika Westerberg 			tb_switch_remove(port->remote->sw);
23623dd5bb4SAndreas Noever 			port->remote = NULL;
237dfe40ca4SMika Westerberg 			if (port->dual_link_port)
238dfe40ca4SMika Westerberg 				port->dual_link_port->remote = NULL;
23923dd5bb4SAndreas Noever 		} else {
24023dd5bb4SAndreas Noever 			tb_free_unplugged_children(port->remote->sw);
24123dd5bb4SAndreas Noever 		}
24223dd5bb4SAndreas Noever 	}
24323dd5bb4SAndreas Noever }
24423dd5bb4SAndreas Noever 
24523dd5bb4SAndreas Noever /**
246e78db6f0SMika Westerberg  * tb_find_port() - return the first port of @type on @sw or NULL
247e78db6f0SMika Westerberg  * @sw: Switch to find the port from
248e78db6f0SMika Westerberg  * @type: Port type to look for
2493364f0c1SAndreas Noever  */
250e78db6f0SMika Westerberg static struct tb_port *tb_find_port(struct tb_switch *sw,
251e78db6f0SMika Westerberg 				    enum tb_port_type type)
2523364f0c1SAndreas Noever {
2533364f0c1SAndreas Noever 	int i;
2543364f0c1SAndreas Noever 	for (i = 1; i <= sw->config.max_port_number; i++)
255e78db6f0SMika Westerberg 		if (sw->ports[i].config.type == type)
2563364f0c1SAndreas Noever 			return &sw->ports[i];
2573364f0c1SAndreas Noever 	return NULL;
2583364f0c1SAndreas Noever }
2593364f0c1SAndreas Noever 
2603364f0c1SAndreas Noever /**
261e78db6f0SMika Westerberg  * tb_find_unused_port() - return the first inactive port on @sw
262e78db6f0SMika Westerberg  * @sw: Switch to find the port on
263e78db6f0SMika Westerberg  * @type: Port type to look for
2643364f0c1SAndreas Noever  */
265e78db6f0SMika Westerberg static struct tb_port *tb_find_unused_port(struct tb_switch *sw,
266e78db6f0SMika Westerberg 					   enum tb_port_type type)
2673364f0c1SAndreas Noever {
2683364f0c1SAndreas Noever 	int i;
269e78db6f0SMika Westerberg 
2703364f0c1SAndreas Noever 	for (i = 1; i <= sw->config.max_port_number; i++) {
2713364f0c1SAndreas Noever 		if (tb_is_upstream_port(&sw->ports[i]))
2723364f0c1SAndreas Noever 			continue;
273e78db6f0SMika Westerberg 		if (sw->ports[i].config.type != type)
2743364f0c1SAndreas Noever 			continue;
275e78db6f0SMika Westerberg 		if (!sw->ports[i].cap_adap)
2763364f0c1SAndreas Noever 			continue;
277e78db6f0SMika Westerberg 		if (tb_port_is_enabled(&sw->ports[i]))
2783364f0c1SAndreas Noever 			continue;
2793364f0c1SAndreas Noever 		return &sw->ports[i];
2803364f0c1SAndreas Noever 	}
2813364f0c1SAndreas Noever 	return NULL;
2823364f0c1SAndreas Noever }
2833364f0c1SAndreas Noever 
28499cabbb0SMika Westerberg static struct tb_port *tb_find_pcie_down(struct tb_switch *sw,
28599cabbb0SMika Westerberg 					 const struct tb_port *port)
2863364f0c1SAndreas Noever {
28799cabbb0SMika Westerberg 	/*
28899cabbb0SMika Westerberg 	 * To keep plugging devices consistently in the same PCIe
28999cabbb0SMika Westerberg 	 * hierarchy, do mapping here for root switch downstream PCIe
29099cabbb0SMika Westerberg 	 * ports.
29199cabbb0SMika Westerberg 	 */
29299cabbb0SMika Westerberg 	if (!tb_route(sw)) {
29399cabbb0SMika Westerberg 		int phy_port = tb_phy_port_from_link(port->port);
29499cabbb0SMika Westerberg 		int index;
29599cabbb0SMika Westerberg 
29699cabbb0SMika Westerberg 		/*
29799cabbb0SMika Westerberg 		 * Hard-coded Thunderbolt port to PCIe down port mapping
29899cabbb0SMika Westerberg 		 * per controller.
29999cabbb0SMika Westerberg 		 */
30099cabbb0SMika Westerberg 		if (tb_switch_is_cr(sw))
30199cabbb0SMika Westerberg 			index = !phy_port ? 6 : 7;
30299cabbb0SMika Westerberg 		else if (tb_switch_is_fr(sw))
30399cabbb0SMika Westerberg 			index = !phy_port ? 6 : 8;
30499cabbb0SMika Westerberg 		else
30599cabbb0SMika Westerberg 			goto out;
30699cabbb0SMika Westerberg 
30799cabbb0SMika Westerberg 		/* Validate the hard-coding */
30899cabbb0SMika Westerberg 		if (WARN_ON(index > sw->config.max_port_number))
30999cabbb0SMika Westerberg 			goto out;
31099cabbb0SMika Westerberg 		if (WARN_ON(!tb_port_is_pcie_down(&sw->ports[index])))
31199cabbb0SMika Westerberg 			goto out;
31299cabbb0SMika Westerberg 		if (WARN_ON(tb_pci_port_is_enabled(&sw->ports[index])))
31399cabbb0SMika Westerberg 			goto out;
31499cabbb0SMika Westerberg 
31599cabbb0SMika Westerberg 		return &sw->ports[index];
31699cabbb0SMika Westerberg 	}
31799cabbb0SMika Westerberg 
31899cabbb0SMika Westerberg out:
319e78db6f0SMika Westerberg 	return tb_find_unused_port(sw, TB_TYPE_PCIE_DOWN);
32099cabbb0SMika Westerberg }
32199cabbb0SMika Westerberg 
3224f807e47SMika Westerberg static int tb_tunnel_dp(struct tb *tb, struct tb_port *out)
3234f807e47SMika Westerberg {
3244f807e47SMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
3254f807e47SMika Westerberg 	struct tb_switch *sw = out->sw;
3264f807e47SMika Westerberg 	struct tb_tunnel *tunnel;
3274f807e47SMika Westerberg 	struct tb_port *in;
3284f807e47SMika Westerberg 
3294f807e47SMika Westerberg 	if (tb_port_is_enabled(out))
3304f807e47SMika Westerberg 		return 0;
3314f807e47SMika Westerberg 
3324f807e47SMika Westerberg 	do {
3334f807e47SMika Westerberg 		sw = tb_to_switch(sw->dev.parent);
3344f807e47SMika Westerberg 		if (!sw)
3354f807e47SMika Westerberg 			return 0;
3364f807e47SMika Westerberg 		in = tb_find_unused_port(sw, TB_TYPE_DP_HDMI_IN);
3374f807e47SMika Westerberg 	} while (!in);
3384f807e47SMika Westerberg 
3394f807e47SMika Westerberg 	tunnel = tb_tunnel_alloc_dp(tb, in, out);
3404f807e47SMika Westerberg 	if (!tunnel) {
3414f807e47SMika Westerberg 		tb_port_dbg(out, "DP tunnel allocation failed\n");
3424f807e47SMika Westerberg 		return -ENOMEM;
3434f807e47SMika Westerberg 	}
3444f807e47SMika Westerberg 
3454f807e47SMika Westerberg 	if (tb_tunnel_activate(tunnel)) {
3464f807e47SMika Westerberg 		tb_port_info(out, "DP tunnel activation failed, aborting\n");
3474f807e47SMika Westerberg 		tb_tunnel_free(tunnel);
3484f807e47SMika Westerberg 		return -EIO;
3494f807e47SMika Westerberg 	}
3504f807e47SMika Westerberg 
3514f807e47SMika Westerberg 	list_add_tail(&tunnel->list, &tcm->tunnel_list);
3524f807e47SMika Westerberg 	return 0;
3534f807e47SMika Westerberg }
3544f807e47SMika Westerberg 
3554f807e47SMika Westerberg static void tb_teardown_dp(struct tb *tb, struct tb_port *out)
3564f807e47SMika Westerberg {
3574f807e47SMika Westerberg 	tb_free_tunnel(tb, TB_TUNNEL_DP, NULL, out);
3584f807e47SMika Westerberg }
3594f807e47SMika Westerberg 
36099cabbb0SMika Westerberg static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
36199cabbb0SMika Westerberg {
36299cabbb0SMika Westerberg 	struct tb_port *up, *down, *port;
3639d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
36499cabbb0SMika Westerberg 	struct tb_switch *parent_sw;
36599cabbb0SMika Westerberg 	struct tb_tunnel *tunnel;
3669d3cce0bSMika Westerberg 
367e78db6f0SMika Westerberg 	up = tb_find_port(sw, TB_TYPE_PCIE_UP);
36899cabbb0SMika Westerberg 	if (!up)
36999cabbb0SMika Westerberg 		return 0;
3703364f0c1SAndreas Noever 
37199cabbb0SMika Westerberg 	/*
37299cabbb0SMika Westerberg 	 * Look up available down port. Since we are chaining it should
37399cabbb0SMika Westerberg 	 * be found right above this switch.
37499cabbb0SMika Westerberg 	 */
37599cabbb0SMika Westerberg 	parent_sw = tb_to_switch(sw->dev.parent);
37699cabbb0SMika Westerberg 	port = tb_port_at(tb_route(sw), parent_sw);
37799cabbb0SMika Westerberg 	down = tb_find_pcie_down(parent_sw, port);
37899cabbb0SMika Westerberg 	if (!down)
37999cabbb0SMika Westerberg 		return 0;
3803364f0c1SAndreas Noever 
38199cabbb0SMika Westerberg 	tunnel = tb_tunnel_alloc_pci(tb, up, down);
38299cabbb0SMika Westerberg 	if (!tunnel)
38399cabbb0SMika Westerberg 		return -ENOMEM;
3843364f0c1SAndreas Noever 
38593f36adeSMika Westerberg 	if (tb_tunnel_activate(tunnel)) {
38699cabbb0SMika Westerberg 		tb_port_info(up,
3873364f0c1SAndreas Noever 			     "PCIe tunnel activation failed, aborting\n");
38893f36adeSMika Westerberg 		tb_tunnel_free(tunnel);
38999cabbb0SMika Westerberg 		return -EIO;
3903364f0c1SAndreas Noever 	}
3913364f0c1SAndreas Noever 
39299cabbb0SMika Westerberg 	list_add_tail(&tunnel->list, &tcm->tunnel_list);
39399cabbb0SMika Westerberg 	return 0;
3943364f0c1SAndreas Noever }
3959da672a4SAndreas Noever 
396d6cc51cdSAndreas Noever /* hotplug handling */
397d6cc51cdSAndreas Noever 
398d6cc51cdSAndreas Noever /**
399d6cc51cdSAndreas Noever  * tb_handle_hotplug() - handle hotplug event
400d6cc51cdSAndreas Noever  *
401d6cc51cdSAndreas Noever  * Executes on tb->wq.
402d6cc51cdSAndreas Noever  */
403d6cc51cdSAndreas Noever static void tb_handle_hotplug(struct work_struct *work)
404d6cc51cdSAndreas Noever {
405d6cc51cdSAndreas Noever 	struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
406d6cc51cdSAndreas Noever 	struct tb *tb = ev->tb;
4079d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
408053596d9SAndreas Noever 	struct tb_switch *sw;
409053596d9SAndreas Noever 	struct tb_port *port;
410d6cc51cdSAndreas Noever 	mutex_lock(&tb->lock);
4119d3cce0bSMika Westerberg 	if (!tcm->hotplug_active)
412d6cc51cdSAndreas Noever 		goto out; /* during init, suspend or shutdown */
413d6cc51cdSAndreas Noever 
4148f965efdSMika Westerberg 	sw = tb_switch_find_by_route(tb, ev->route);
415053596d9SAndreas Noever 	if (!sw) {
416053596d9SAndreas Noever 		tb_warn(tb,
417053596d9SAndreas Noever 			"hotplug event from non existent switch %llx:%x (unplug: %d)\n",
418053596d9SAndreas Noever 			ev->route, ev->port, ev->unplug);
419053596d9SAndreas Noever 		goto out;
420053596d9SAndreas Noever 	}
421053596d9SAndreas Noever 	if (ev->port > sw->config.max_port_number) {
422053596d9SAndreas Noever 		tb_warn(tb,
423053596d9SAndreas Noever 			"hotplug event from non existent port %llx:%x (unplug: %d)\n",
424053596d9SAndreas Noever 			ev->route, ev->port, ev->unplug);
4258f965efdSMika Westerberg 		goto put_sw;
426053596d9SAndreas Noever 	}
427053596d9SAndreas Noever 	port = &sw->ports[ev->port];
428053596d9SAndreas Noever 	if (tb_is_upstream_port(port)) {
429dfe40ca4SMika Westerberg 		tb_dbg(tb, "hotplug event for upstream port %llx:%x (unplug: %d)\n",
430053596d9SAndreas Noever 		       ev->route, ev->port, ev->unplug);
4318f965efdSMika Westerberg 		goto put_sw;
432053596d9SAndreas Noever 	}
433053596d9SAndreas Noever 	if (ev->unplug) {
434dfe40ca4SMika Westerberg 		if (tb_port_has_remote(port)) {
435053596d9SAndreas Noever 			tb_port_info(port, "unplugged\n");
436aae20bb6SLukas Wunner 			tb_sw_set_unplugged(port->remote->sw);
4373364f0c1SAndreas Noever 			tb_free_invalid_tunnels(tb);
438bfe778acSMika Westerberg 			tb_switch_remove(port->remote->sw);
439053596d9SAndreas Noever 			port->remote = NULL;
440dfe40ca4SMika Westerberg 			if (port->dual_link_port)
441dfe40ca4SMika Westerberg 				port->dual_link_port->remote = NULL;
4424f807e47SMika Westerberg 		} else if (tb_port_is_dpout(port)) {
4434f807e47SMika Westerberg 			tb_teardown_dp(tb, port);
444053596d9SAndreas Noever 		} else {
445053596d9SAndreas Noever 			tb_port_info(port,
446053596d9SAndreas Noever 				     "got unplug event for disconnected port, ignoring\n");
447053596d9SAndreas Noever 		}
448053596d9SAndreas Noever 	} else if (port->remote) {
449053596d9SAndreas Noever 		tb_port_info(port,
450053596d9SAndreas Noever 			     "got plug event for connected port, ignoring\n");
451053596d9SAndreas Noever 	} else {
452344e0643SMika Westerberg 		if (tb_port_is_null(port)) {
453053596d9SAndreas Noever 			tb_port_info(port, "hotplug: scanning\n");
454053596d9SAndreas Noever 			tb_scan_port(port);
45599cabbb0SMika Westerberg 			if (!port->remote)
456053596d9SAndreas Noever 				tb_port_info(port, "hotplug: no switch found\n");
4574f807e47SMika Westerberg 		} else if (tb_port_is_dpout(port)) {
4584f807e47SMika Westerberg 			tb_tunnel_dp(tb, port);
459053596d9SAndreas Noever 		}
460344e0643SMika Westerberg 	}
4618f965efdSMika Westerberg 
4628f965efdSMika Westerberg put_sw:
4638f965efdSMika Westerberg 	tb_switch_put(sw);
464d6cc51cdSAndreas Noever out:
465d6cc51cdSAndreas Noever 	mutex_unlock(&tb->lock);
466d6cc51cdSAndreas Noever 	kfree(ev);
467d6cc51cdSAndreas Noever }
468d6cc51cdSAndreas Noever 
469d6cc51cdSAndreas Noever /**
470d6cc51cdSAndreas Noever  * tb_schedule_hotplug_handler() - callback function for the control channel
471d6cc51cdSAndreas Noever  *
472d6cc51cdSAndreas Noever  * Delegates to tb_handle_hotplug.
473d6cc51cdSAndreas Noever  */
47481a54b5eSMika Westerberg static void tb_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
47581a54b5eSMika Westerberg 			    const void *buf, size_t size)
476d6cc51cdSAndreas Noever {
47781a54b5eSMika Westerberg 	const struct cfg_event_pkg *pkg = buf;
47881a54b5eSMika Westerberg 	u64 route;
47981a54b5eSMika Westerberg 
48081a54b5eSMika Westerberg 	if (type != TB_CFG_PKG_EVENT) {
48181a54b5eSMika Westerberg 		tb_warn(tb, "unexpected event %#x, ignoring\n", type);
48281a54b5eSMika Westerberg 		return;
48381a54b5eSMika Westerberg 	}
48481a54b5eSMika Westerberg 
48581a54b5eSMika Westerberg 	route = tb_cfg_get_route(&pkg->header);
48681a54b5eSMika Westerberg 
48781a54b5eSMika Westerberg 	if (tb_cfg_error(tb->ctl, route, pkg->port,
48881a54b5eSMika Westerberg 			 TB_CFG_ERROR_ACK_PLUG_EVENT)) {
48981a54b5eSMika Westerberg 		tb_warn(tb, "could not ack plug event on %llx:%x\n", route,
49081a54b5eSMika Westerberg 			pkg->port);
49181a54b5eSMika Westerberg 	}
49281a54b5eSMika Westerberg 
4934f807e47SMika Westerberg 	tb_queue_hotplug(tb, route, pkg->port, pkg->unplug);
494d6cc51cdSAndreas Noever }
495d6cc51cdSAndreas Noever 
4969d3cce0bSMika Westerberg static void tb_stop(struct tb *tb)
497d6cc51cdSAndreas Noever {
4989d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
49993f36adeSMika Westerberg 	struct tb_tunnel *tunnel;
50093f36adeSMika Westerberg 	struct tb_tunnel *n;
5013364f0c1SAndreas Noever 
5023364f0c1SAndreas Noever 	/* tunnels are only present after everything has been initialized */
5039d3cce0bSMika Westerberg 	list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
50493f36adeSMika Westerberg 		tb_tunnel_deactivate(tunnel);
50593f36adeSMika Westerberg 		tb_tunnel_free(tunnel);
5063364f0c1SAndreas Noever 	}
507bfe778acSMika Westerberg 	tb_switch_remove(tb->root_switch);
5089d3cce0bSMika Westerberg 	tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
509d6cc51cdSAndreas Noever }
510d6cc51cdSAndreas Noever 
51199cabbb0SMika Westerberg static int tb_scan_finalize_switch(struct device *dev, void *data)
51299cabbb0SMika Westerberg {
51399cabbb0SMika Westerberg 	if (tb_is_switch(dev)) {
51499cabbb0SMika Westerberg 		struct tb_switch *sw = tb_to_switch(dev);
51599cabbb0SMika Westerberg 
51699cabbb0SMika Westerberg 		/*
51799cabbb0SMika Westerberg 		 * If we found that the switch was already setup by the
51899cabbb0SMika Westerberg 		 * boot firmware, mark it as authorized now before we
51999cabbb0SMika Westerberg 		 * send uevent to userspace.
52099cabbb0SMika Westerberg 		 */
52199cabbb0SMika Westerberg 		if (sw->boot)
52299cabbb0SMika Westerberg 			sw->authorized = 1;
52399cabbb0SMika Westerberg 
52499cabbb0SMika Westerberg 		dev_set_uevent_suppress(dev, false);
52599cabbb0SMika Westerberg 		kobject_uevent(&dev->kobj, KOBJ_ADD);
52699cabbb0SMika Westerberg 		device_for_each_child(dev, NULL, tb_scan_finalize_switch);
52799cabbb0SMika Westerberg 	}
52899cabbb0SMika Westerberg 
52999cabbb0SMika Westerberg 	return 0;
53099cabbb0SMika Westerberg }
53199cabbb0SMika Westerberg 
5329d3cce0bSMika Westerberg static int tb_start(struct tb *tb)
533d6cc51cdSAndreas Noever {
5349d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
535bfe778acSMika Westerberg 	int ret;
536d6cc51cdSAndreas Noever 
537bfe778acSMika Westerberg 	tb->root_switch = tb_switch_alloc(tb, &tb->dev, 0);
538a25c8b2fSAndreas Noever 	if (!tb->root_switch)
5399d3cce0bSMika Westerberg 		return -ENOMEM;
540a25c8b2fSAndreas Noever 
541e6b245ccSMika Westerberg 	/*
542e6b245ccSMika Westerberg 	 * ICM firmware upgrade needs running firmware and in native
543e6b245ccSMika Westerberg 	 * mode that is not available so disable firmware upgrade of the
544e6b245ccSMika Westerberg 	 * root switch.
545e6b245ccSMika Westerberg 	 */
546e6b245ccSMika Westerberg 	tb->root_switch->no_nvm_upgrade = true;
547e6b245ccSMika Westerberg 
548bfe778acSMika Westerberg 	ret = tb_switch_configure(tb->root_switch);
549bfe778acSMika Westerberg 	if (ret) {
550bfe778acSMika Westerberg 		tb_switch_put(tb->root_switch);
551bfe778acSMika Westerberg 		return ret;
552bfe778acSMika Westerberg 	}
553bfe778acSMika Westerberg 
554bfe778acSMika Westerberg 	/* Announce the switch to the world */
555bfe778acSMika Westerberg 	ret = tb_switch_add(tb->root_switch);
556bfe778acSMika Westerberg 	if (ret) {
557bfe778acSMika Westerberg 		tb_switch_put(tb->root_switch);
558bfe778acSMika Westerberg 		return ret;
559bfe778acSMika Westerberg 	}
560bfe778acSMika Westerberg 
5619da672a4SAndreas Noever 	/* Full scan to discover devices added before the driver was loaded. */
5629da672a4SAndreas Noever 	tb_scan_switch(tb->root_switch);
5630414bec5SMika Westerberg 	/* Find out tunnels created by the boot firmware */
5640414bec5SMika Westerberg 	tb_discover_tunnels(tb->root_switch);
56599cabbb0SMika Westerberg 	/* Make the discovered switches available to the userspace */
56699cabbb0SMika Westerberg 	device_for_each_child(&tb->root_switch->dev, NULL,
56799cabbb0SMika Westerberg 			      tb_scan_finalize_switch);
5689da672a4SAndreas Noever 
569d6cc51cdSAndreas Noever 	/* Allow tb_handle_hotplug to progress events */
5709d3cce0bSMika Westerberg 	tcm->hotplug_active = true;
5719d3cce0bSMika Westerberg 	return 0;
572d6cc51cdSAndreas Noever }
573d6cc51cdSAndreas Noever 
5749d3cce0bSMika Westerberg static int tb_suspend_noirq(struct tb *tb)
57523dd5bb4SAndreas Noever {
5769d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
5779d3cce0bSMika Westerberg 
578daa5140fSMika Westerberg 	tb_dbg(tb, "suspending...\n");
57923dd5bb4SAndreas Noever 	tb_switch_suspend(tb->root_switch);
5809d3cce0bSMika Westerberg 	tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
581daa5140fSMika Westerberg 	tb_dbg(tb, "suspend finished\n");
5829d3cce0bSMika Westerberg 
5839d3cce0bSMika Westerberg 	return 0;
58423dd5bb4SAndreas Noever }
58523dd5bb4SAndreas Noever 
5869d3cce0bSMika Westerberg static int tb_resume_noirq(struct tb *tb)
58723dd5bb4SAndreas Noever {
5889d3cce0bSMika Westerberg 	struct tb_cm *tcm = tb_priv(tb);
58993f36adeSMika Westerberg 	struct tb_tunnel *tunnel, *n;
5909d3cce0bSMika Westerberg 
591daa5140fSMika Westerberg 	tb_dbg(tb, "resuming...\n");
59223dd5bb4SAndreas Noever 
59323dd5bb4SAndreas Noever 	/* remove any pci devices the firmware might have setup */
59423dd5bb4SAndreas Noever 	tb_switch_reset(tb, 0);
59523dd5bb4SAndreas Noever 
59623dd5bb4SAndreas Noever 	tb_switch_resume(tb->root_switch);
59723dd5bb4SAndreas Noever 	tb_free_invalid_tunnels(tb);
59823dd5bb4SAndreas Noever 	tb_free_unplugged_children(tb->root_switch);
5999d3cce0bSMika Westerberg 	list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)
60093f36adeSMika Westerberg 		tb_tunnel_restart(tunnel);
6019d3cce0bSMika Westerberg 	if (!list_empty(&tcm->tunnel_list)) {
60223dd5bb4SAndreas Noever 		/*
60323dd5bb4SAndreas Noever 		 * the pcie links need some time to get going.
60423dd5bb4SAndreas Noever 		 * 100ms works for me...
60523dd5bb4SAndreas Noever 		 */
606daa5140fSMika Westerberg 		tb_dbg(tb, "tunnels restarted, sleeping for 100ms\n");
60723dd5bb4SAndreas Noever 		msleep(100);
60823dd5bb4SAndreas Noever 	}
60923dd5bb4SAndreas Noever 	 /* Allow tb_handle_hotplug to progress events */
6109d3cce0bSMika Westerberg 	tcm->hotplug_active = true;
611daa5140fSMika Westerberg 	tb_dbg(tb, "resume finished\n");
6129d3cce0bSMika Westerberg 
6139d3cce0bSMika Westerberg 	return 0;
6149d3cce0bSMika Westerberg }
6159d3cce0bSMika Westerberg 
6169d3cce0bSMika Westerberg static const struct tb_cm_ops tb_cm_ops = {
6179d3cce0bSMika Westerberg 	.start = tb_start,
6189d3cce0bSMika Westerberg 	.stop = tb_stop,
6199d3cce0bSMika Westerberg 	.suspend_noirq = tb_suspend_noirq,
6209d3cce0bSMika Westerberg 	.resume_noirq = tb_resume_noirq,
62181a54b5eSMika Westerberg 	.handle_event = tb_handle_event,
62299cabbb0SMika Westerberg 	.approve_switch = tb_tunnel_pci,
6239d3cce0bSMika Westerberg };
6249d3cce0bSMika Westerberg 
6259d3cce0bSMika Westerberg struct tb *tb_probe(struct tb_nhi *nhi)
6269d3cce0bSMika Westerberg {
6279d3cce0bSMika Westerberg 	struct tb_cm *tcm;
6289d3cce0bSMika Westerberg 	struct tb *tb;
6299d3cce0bSMika Westerberg 
630630b3affSLukas Wunner 	if (!x86_apple_machine)
631f67cf491SMika Westerberg 		return NULL;
632f67cf491SMika Westerberg 
6339d3cce0bSMika Westerberg 	tb = tb_domain_alloc(nhi, sizeof(*tcm));
6349d3cce0bSMika Westerberg 	if (!tb)
6359d3cce0bSMika Westerberg 		return NULL;
6369d3cce0bSMika Westerberg 
63799cabbb0SMika Westerberg 	tb->security_level = TB_SECURITY_USER;
6389d3cce0bSMika Westerberg 	tb->cm_ops = &tb_cm_ops;
6399d3cce0bSMika Westerberg 
6409d3cce0bSMika Westerberg 	tcm = tb_priv(tb);
6419d3cce0bSMika Westerberg 	INIT_LIST_HEAD(&tcm->tunnel_list);
6429d3cce0bSMika Westerberg 
6439d3cce0bSMika Westerberg 	return tb;
64423dd5bb4SAndreas Noever }
645