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