Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.17-rc6 226 lines 6.5 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Thunderbolt Cactus Ridge driver - PCIe tunnel 4 * 5 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> 6 */ 7 8#include <linux/slab.h> 9#include <linux/list.h> 10 11#include "tunnel_pci.h" 12#include "tb.h" 13 14#define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \ 15 do { \ 16 struct tb_pci_tunnel *__tunnel = (tunnel); \ 17 level(__tunnel->tb, "%llx:%x <-> %llx:%x (PCI): " fmt, \ 18 tb_route(__tunnel->down_port->sw), \ 19 __tunnel->down_port->port, \ 20 tb_route(__tunnel->up_port->sw), \ 21 __tunnel->up_port->port, \ 22 ## arg); \ 23 } while (0) 24 25#define tb_tunnel_WARN(tunnel, fmt, arg...) \ 26 __TB_TUNNEL_PRINT(tb_WARN, tunnel, fmt, ##arg) 27#define tb_tunnel_warn(tunnel, fmt, arg...) \ 28 __TB_TUNNEL_PRINT(tb_warn, tunnel, fmt, ##arg) 29#define tb_tunnel_info(tunnel, fmt, arg...) \ 30 __TB_TUNNEL_PRINT(tb_info, tunnel, fmt, ##arg) 31 32static void tb_pci_init_path(struct tb_path *path) 33{ 34 path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL; 35 path->egress_shared_buffer = TB_PATH_NONE; 36 path->ingress_fc_enable = TB_PATH_ALL; 37 path->ingress_shared_buffer = TB_PATH_NONE; 38 path->priority = 3; 39 path->weight = 1; 40 path->drop_packages = 0; 41 path->nfc_credits = 0; 42} 43 44/** 45 * tb_pci_alloc() - allocate a pci tunnel 46 * 47 * Allocate a PCI tunnel. The ports must be of type TB_TYPE_PCIE_UP and 48 * TB_TYPE_PCIE_DOWN. 49 * 50 * Currently only paths consisting of two hops are supported (that is the 51 * ports must be on "adjacent" switches). 52 * 53 * The paths are hard-coded to use hop 8 (the only working hop id available on 54 * my thunderbolt devices). Therefore at most ONE path per device may be 55 * activated. 56 * 57 * Return: Returns a tb_pci_tunnel on success or NULL on failure. 58 */ 59struct tb_pci_tunnel *tb_pci_alloc(struct tb *tb, struct tb_port *up, 60 struct tb_port *down) 61{ 62 struct tb_pci_tunnel *tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL); 63 if (!tunnel) 64 goto err; 65 tunnel->tb = tb; 66 tunnel->down_port = down; 67 tunnel->up_port = up; 68 INIT_LIST_HEAD(&tunnel->list); 69 tunnel->path_to_up = tb_path_alloc(up->sw->tb, 2); 70 if (!tunnel->path_to_up) 71 goto err; 72 tunnel->path_to_down = tb_path_alloc(up->sw->tb, 2); 73 if (!tunnel->path_to_down) 74 goto err; 75 tb_pci_init_path(tunnel->path_to_up); 76 tb_pci_init_path(tunnel->path_to_down); 77 78 tunnel->path_to_up->hops[0].in_port = down; 79 tunnel->path_to_up->hops[0].in_hop_index = 8; 80 tunnel->path_to_up->hops[0].in_counter_index = -1; 81 tunnel->path_to_up->hops[0].out_port = tb_upstream_port(up->sw)->remote; 82 tunnel->path_to_up->hops[0].next_hop_index = 8; 83 84 tunnel->path_to_up->hops[1].in_port = tb_upstream_port(up->sw); 85 tunnel->path_to_up->hops[1].in_hop_index = 8; 86 tunnel->path_to_up->hops[1].in_counter_index = -1; 87 tunnel->path_to_up->hops[1].out_port = up; 88 tunnel->path_to_up->hops[1].next_hop_index = 8; 89 90 tunnel->path_to_down->hops[0].in_port = up; 91 tunnel->path_to_down->hops[0].in_hop_index = 8; 92 tunnel->path_to_down->hops[0].in_counter_index = -1; 93 tunnel->path_to_down->hops[0].out_port = tb_upstream_port(up->sw); 94 tunnel->path_to_down->hops[0].next_hop_index = 8; 95 96 tunnel->path_to_down->hops[1].in_port = 97 tb_upstream_port(up->sw)->remote; 98 tunnel->path_to_down->hops[1].in_hop_index = 8; 99 tunnel->path_to_down->hops[1].in_counter_index = -1; 100 tunnel->path_to_down->hops[1].out_port = down; 101 tunnel->path_to_down->hops[1].next_hop_index = 8; 102 return tunnel; 103 104err: 105 if (tunnel) { 106 if (tunnel->path_to_down) 107 tb_path_free(tunnel->path_to_down); 108 if (tunnel->path_to_up) 109 tb_path_free(tunnel->path_to_up); 110 kfree(tunnel); 111 } 112 return NULL; 113} 114 115/** 116 * tb_pci_free() - free a tunnel 117 * 118 * The tunnel must have been deactivated. 119 */ 120void tb_pci_free(struct tb_pci_tunnel *tunnel) 121{ 122 if (tunnel->path_to_up->activated || tunnel->path_to_down->activated) { 123 tb_tunnel_WARN(tunnel, "trying to free an activated tunnel\n"); 124 return; 125 } 126 tb_path_free(tunnel->path_to_up); 127 tb_path_free(tunnel->path_to_down); 128 kfree(tunnel); 129} 130 131/** 132 * tb_pci_is_invalid - check whether an activated path is still valid 133 */ 134bool tb_pci_is_invalid(struct tb_pci_tunnel *tunnel) 135{ 136 WARN_ON(!tunnel->path_to_up->activated); 137 WARN_ON(!tunnel->path_to_down->activated); 138 139 return tb_path_is_invalid(tunnel->path_to_up) 140 || tb_path_is_invalid(tunnel->path_to_down); 141} 142 143/** 144 * tb_pci_port_active() - activate/deactivate PCI capability 145 * 146 * Return: Returns 0 on success or an error code on failure. 147 */ 148static int tb_pci_port_active(struct tb_port *port, bool active) 149{ 150 u32 word = active ? 0x80000000 : 0x0; 151 int cap = tb_port_find_cap(port, TB_PORT_CAP_ADAP); 152 if (cap < 0) { 153 tb_port_warn(port, "TB_PORT_CAP_ADAP not found: %d\n", cap); 154 return cap; 155 } 156 return tb_port_write(port, &word, TB_CFG_PORT, cap, 1); 157} 158 159/** 160 * tb_pci_restart() - activate a tunnel after a hardware reset 161 */ 162int tb_pci_restart(struct tb_pci_tunnel *tunnel) 163{ 164 int res; 165 tunnel->path_to_up->activated = false; 166 tunnel->path_to_down->activated = false; 167 168 tb_tunnel_info(tunnel, "activating\n"); 169 170 res = tb_path_activate(tunnel->path_to_up); 171 if (res) 172 goto err; 173 res = tb_path_activate(tunnel->path_to_down); 174 if (res) 175 goto err; 176 177 res = tb_pci_port_active(tunnel->down_port, true); 178 if (res) 179 goto err; 180 181 res = tb_pci_port_active(tunnel->up_port, true); 182 if (res) 183 goto err; 184 return 0; 185err: 186 tb_tunnel_warn(tunnel, "activation failed\n"); 187 tb_pci_deactivate(tunnel); 188 return res; 189} 190 191/** 192 * tb_pci_activate() - activate a tunnel 193 * 194 * Return: Returns 0 on success or an error code on failure. 195 */ 196int tb_pci_activate(struct tb_pci_tunnel *tunnel) 197{ 198 if (tunnel->path_to_up->activated || tunnel->path_to_down->activated) { 199 tb_tunnel_WARN(tunnel, 200 "trying to activate an already activated tunnel\n"); 201 return -EINVAL; 202 } 203 204 return tb_pci_restart(tunnel); 205} 206 207 208 209/** 210 * tb_pci_deactivate() - deactivate a tunnel 211 */ 212void tb_pci_deactivate(struct tb_pci_tunnel *tunnel) 213{ 214 tb_tunnel_info(tunnel, "deactivating\n"); 215 /* 216 * TODO: enable reset by writing 0x04000000 to TB_CAP_PCIE + 1 on up 217 * port. Seems to have no effect? 218 */ 219 tb_pci_port_active(tunnel->up_port, false); 220 tb_pci_port_active(tunnel->down_port, false); 221 if (tunnel->path_to_down->activated) 222 tb_path_deactivate(tunnel->path_to_down); 223 if (tunnel->path_to_up->activated) 224 tb_path_deactivate(tunnel->path_to_up); 225} 226