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

thunderbolt: Add support for retimer NVM upgrade when there is no link

With help from platform firmware (ACPI) it is possible to power on
retimers even when there is no USB4 link (e.g nothing is connected to
the USB4 ports). This allows us to bring the USB4 sideband up so that we
can access retimers and upgrade their NVM firmware.

If the platform has support for this, we expose two additional
attributes under USB4 ports: offline and rescan. These can be used to
bring the port offline, rescan for the retimers and put the port online
again. The retimer NVM upgrade itself works the same way than with cable
connected.

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
Co-developed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Rajmohan Mani and committed by
Mika Westerberg
3fb10ea4 3406de7c

+277 -28
+26
Documentation/ABI/testing/sysfs-bus-thunderbolt
··· 297 297 Description: Returns the current link mode. Possible values are 298 298 "usb4", "tbt" and "none". 299 299 300 + What: /sys/bus/thunderbolt/devices/usb4_portX/offline 301 + Date: Sep 2021 302 + KernelVersion: v5.14 303 + Contact: Rajmohan Mani <rajmohan.mani@intel.com> 304 + Description: Writing 1 to this attribute puts the USB4 port into 305 + offline mode. Only allowed when there is nothing 306 + connected to the port (link attribute returns "none"). 307 + Once the port is in offline mode it does not receive any 308 + hotplug events. This is used to update NVM firmware of 309 + on-board retimers. Writing 0 puts the port back to 310 + online mode. 311 + 312 + This attribute is only visible if the platform supports 313 + powering on retimers when there is no cable connected. 314 + 315 + What: /sys/bus/thunderbolt/devices/usb4_portX/rescan 316 + Date: Sep 2021 317 + KernelVersion: v5.14 318 + Contact: Rajmohan Mani <rajmohan.mani@intel.com> 319 + Description: When the USB4 port is in offline mode writing 1 to this 320 + attribute forces rescan of the sideband for on-board 321 + retimers. Each retimer appear under the USB4 port as if 322 + the USB4 link was up. These retimers act in the same way 323 + as if the cable was connected so upgrading their NVM 324 + firmware can be done the usual way. 325 + 300 326 What: /sys/bus/thunderbolt/devices/<device>:<port>.<index>/device 301 327 Date: Oct 2020 302 328 KernelVersion: v5.9
+29
Documentation/admin-guide/thunderbolt.rst
··· 256 256 depend on the order they are registered in the NVMem subsystem. N in 257 257 the name is the identifier added by the NVMem subsystem. 258 258 259 + Upgrading on-board retimer NVM when there is no cable connected 260 + --------------------------------------------------------------- 261 + If the platform supports, it may be possible to upgrade the retimer NVM 262 + firmware even when there is nothing connected to the USB4 263 + ports. When this is the case the ``usb4_portX`` devices have two special 264 + attributes: ``offline`` and ``rescan``. The way to upgrade the firmware 265 + is to first put the USB4 port into offline mode:: 266 + 267 + # echo 1 > /sys/bus/thunderbolt/devices/0-0/usb4_port1/offline 268 + 269 + This step makes sure the port does not respond to any hotplug events, 270 + and also ensures the retimers are powered on. The next step is to scan 271 + for the retimers:: 272 + 273 + # echo 1 > /sys/bus/thunderbolt/devices/0-0/usb4_port1/rescan 274 + 275 + This enumerates and adds the on-board retimers. Now retimer NVM can be 276 + upgraded in the same way than with cable connected (see previous 277 + section). However, the retimer is not disconnected as we are offline 278 + mode) so after writing ``1`` to ``nvm_authenticate`` one should wait for 279 + 5 or more seconds before running rescan again:: 280 + 281 + # echo 1 > /sys/bus/thunderbolt/devices/0-0/usb4_port1/rescan 282 + 283 + This point if everything went fine, the port can be put back to 284 + functional state again:: 285 + 286 + # echo 0 > /sys/bus/thunderbolt/devices/0-0/usb4_port1/offline 287 + 259 288 Upgrading NVM when host controller is in safe mode 260 289 -------------------------------------------------- 261 290 If the existing NVM is not properly authenticated (or is missing) the
+15 -9
drivers/thunderbolt/retimer.c
··· 401 401 /** 402 402 * tb_retimer_scan() - Scan for on-board retimers under port 403 403 * @port: USB4 port to scan 404 + * @add: If true also registers found retimers 404 405 * 405 - * Tries to enumerate on-board retimers connected to @port. Found 406 - * retimers are registered as children of @port. Does not scan for cable 407 - * retimers for now. 406 + * Brings the sideband into a state where retimers can be accessed. 407 + * Then Tries to enumerate on-board retimers connected to @port. Found 408 + * retimers are registered as children of @port if @add is set. Does 409 + * not scan for cable retimers for now. 408 410 */ 409 - int tb_retimer_scan(struct tb_port *port) 411 + int tb_retimer_scan(struct tb_port *port, bool add) 410 412 { 411 413 u32 status[TB_MAX_RETIMER_INDEX + 1] = {}; 412 414 int ret, i, last_idx = 0; 413 - 414 - if (!port->cap_usb4) 415 - return 0; 416 415 417 416 /* 418 417 * Send broadcast RT to make sure retimer indices facing this ··· 420 421 ret = usb4_port_enumerate_retimers(port); 421 422 if (ret) 422 423 return ret; 424 + 425 + /* 426 + * Enable sideband channel for each retimer. We can do this 427 + * regardless whether there is device connected or not. 428 + */ 429 + for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) 430 + usb4_port_retimer_set_inbound_sbtx(port, i); 423 431 424 432 /* 425 433 * Before doing anything else, read the authentication status. ··· 459 453 rt = tb_port_find_retimer(port, i); 460 454 if (rt) { 461 455 put_device(&rt->dev); 462 - } else { 456 + } else if (add) { 463 457 ret = tb_retimer_add(port, i, status[i]); 464 458 if (ret && ret != -EOPNOTSUPP) 465 - return ret; 459 + break; 466 460 } 467 461 } 468 462
+32 -16
drivers/thunderbolt/switch.c
··· 1153 1153 return ret == -EINVAL ? 0 : ret; 1154 1154 } 1155 1155 1156 + /* 1157 + * Returns true if the port had something (router, XDomain) connected 1158 + * before suspend. 1159 + */ 1160 + static bool tb_port_resume(struct tb_port *port) 1161 + { 1162 + bool has_remote = tb_port_has_remote(port); 1163 + 1164 + if (port->usb4) { 1165 + usb4_port_device_resume(port->usb4); 1166 + } else if (!has_remote) { 1167 + /* 1168 + * For disconnected downstream lane adapters start lane 1169 + * initialization now so we detect future connects. 1170 + * 1171 + * For XDomain start the lane initialzation now so the 1172 + * link gets re-established. 1173 + * 1174 + * This is only needed for non-USB4 ports. 1175 + */ 1176 + if (!tb_is_upstream_port(port) || port->xdomain) 1177 + tb_port_start_lane_initialization(port); 1178 + } 1179 + 1180 + return has_remote || port->xdomain; 1181 + } 1182 + 1156 1183 /** 1157 1184 * tb_port_is_enabled() - Is the adapter port enabled 1158 1185 * @port: Port to check ··· 2942 2915 2943 2916 /* check for surviving downstream switches */ 2944 2917 tb_switch_for_each_port(sw, port) { 2945 - if (!tb_port_has_remote(port) && !port->xdomain) { 2946 - /* 2947 - * For disconnected downstream lane adapters 2948 - * start lane initialization now so we detect 2949 - * future connects. 2950 - */ 2951 - if (!tb_is_upstream_port(port) && tb_port_is_null(port)) 2952 - tb_port_start_lane_initialization(port); 2918 + if (!tb_port_is_null(port)) 2953 2919 continue; 2954 - } else if (port->xdomain) { 2955 - /* 2956 - * Start lane initialization for XDomain so the 2957 - * link gets re-established. 2958 - */ 2959 - tb_port_start_lane_initialization(port); 2960 - } 2920 + 2921 + if (!tb_port_resume(port)) 2922 + continue; 2961 2923 2962 2924 if (tb_wait_for_port(port, true) <= 0) { 2963 2925 tb_port_warn(port, ··· 2955 2939 tb_sw_set_unplugged(port->remote->sw); 2956 2940 else if (port->xdomain) 2957 2941 port->xdomain->is_unplugged = true; 2958 - } else if (tb_port_has_remote(port) || port->xdomain) { 2942 + } else { 2959 2943 /* 2960 2944 * Always unlock the port so the downstream 2961 2945 * switch/domain is accessible.
+2 -2
drivers/thunderbolt/tb.c
··· 595 595 return; 596 596 } 597 597 598 - tb_retimer_scan(port); 598 + tb_retimer_scan(port, true); 599 599 600 600 sw = tb_switch_alloc(port->sw->tb, &port->sw->dev, 601 601 tb_downstream_route(port)); ··· 662 662 tb_sw_warn(sw, "failed to enable TMU\n"); 663 663 664 664 /* Scan upstream retimers */ 665 - tb_retimer_scan(upstream_port); 665 + tb_retimer_scan(upstream_port, true); 666 666 667 667 /* 668 668 * Create USB 3.x tunnels only when the switch is plugged to the
+4 -1
drivers/thunderbolt/tb.h
··· 249 249 * @port: Pointer to the lane 0 adapter 250 250 * @can_offline: Does the port have necessary platform support to moved 251 251 * it into offline mode and back 252 + * @offline: The port is currently in offline mode 252 253 */ 253 254 struct usb4_port { 254 255 struct device dev; 255 256 struct tb_port *port; 256 257 bool can_offline; 258 + bool offline; 257 259 }; 258 260 259 261 /** ··· 1019 1017 struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, 1020 1018 u8 depth); 1021 1019 1022 - int tb_retimer_scan(struct tb_port *port); 1020 + int tb_retimer_scan(struct tb_port *port, bool add); 1023 1021 void tb_retimer_remove_all(struct tb_port *port); 1024 1022 1025 1023 static inline bool tb_is_retimer(const struct device *dev) ··· 1107 1105 1108 1106 struct usb4_port *usb4_port_device_add(struct tb_port *port); 1109 1107 void usb4_port_device_remove(struct usb4_port *usb4); 1108 + int usb4_port_device_resume(struct usb4_port *usb4); 1110 1109 1111 1110 /* Keep link controller awake during update */ 1112 1111 #define QUIRK_FORCE_POWER_LINK_CONTROLLER BIT(0)
+169
drivers/thunderbolt/usb4_port.c
··· 44 44 .attrs = common_attrs, 45 45 }; 46 46 47 + static int usb4_port_offline(struct usb4_port *usb4) 48 + { 49 + struct tb_port *port = usb4->port; 50 + int ret; 51 + 52 + ret = tb_acpi_power_on_retimers(port); 53 + if (ret) 54 + return ret; 55 + 56 + ret = usb4_port_router_offline(port); 57 + if (ret) { 58 + tb_acpi_power_off_retimers(port); 59 + return ret; 60 + } 61 + 62 + ret = tb_retimer_scan(port, false); 63 + if (ret) { 64 + usb4_port_router_online(port); 65 + tb_acpi_power_off_retimers(port); 66 + } 67 + 68 + return ret; 69 + } 70 + 71 + static void usb4_port_online(struct usb4_port *usb4) 72 + { 73 + struct tb_port *port = usb4->port; 74 + 75 + usb4_port_router_online(port); 76 + tb_acpi_power_off_retimers(port); 77 + } 78 + 79 + static ssize_t offline_show(struct device *dev, 80 + struct device_attribute *attr, char *buf) 81 + { 82 + struct usb4_port *usb4 = tb_to_usb4_port_device(dev); 83 + 84 + return sysfs_emit(buf, "%d\n", usb4->offline); 85 + } 86 + 87 + static ssize_t offline_store(struct device *dev, 88 + struct device_attribute *attr, const char *buf, size_t count) 89 + { 90 + struct usb4_port *usb4 = tb_to_usb4_port_device(dev); 91 + struct tb_port *port = usb4->port; 92 + struct tb *tb = port->sw->tb; 93 + bool val; 94 + int ret; 95 + 96 + ret = kstrtobool(buf, &val); 97 + if (ret) 98 + return ret; 99 + 100 + pm_runtime_get_sync(&usb4->dev); 101 + 102 + if (mutex_lock_interruptible(&tb->lock)) { 103 + ret = -ERESTARTSYS; 104 + goto out_rpm; 105 + } 106 + 107 + if (val == usb4->offline) 108 + goto out_unlock; 109 + 110 + /* Offline mode works only for ports that are not connected */ 111 + if (tb_port_has_remote(port)) { 112 + ret = -EBUSY; 113 + goto out_unlock; 114 + } 115 + 116 + if (val) { 117 + ret = usb4_port_offline(usb4); 118 + if (ret) 119 + goto out_unlock; 120 + } else { 121 + usb4_port_online(usb4); 122 + tb_retimer_remove_all(port); 123 + } 124 + 125 + usb4->offline = val; 126 + tb_port_dbg(port, "%s offline mode\n", val ? "enter" : "exit"); 127 + 128 + out_unlock: 129 + mutex_unlock(&tb->lock); 130 + out_rpm: 131 + pm_runtime_mark_last_busy(&usb4->dev); 132 + pm_runtime_put_autosuspend(&usb4->dev); 133 + 134 + return ret ? ret : count; 135 + } 136 + static DEVICE_ATTR_RW(offline); 137 + 138 + static ssize_t rescan_store(struct device *dev, 139 + struct device_attribute *attr, const char *buf, size_t count) 140 + { 141 + struct usb4_port *usb4 = tb_to_usb4_port_device(dev); 142 + struct tb_port *port = usb4->port; 143 + struct tb *tb = port->sw->tb; 144 + bool val; 145 + int ret; 146 + 147 + ret = kstrtobool(buf, &val); 148 + if (ret) 149 + return ret; 150 + 151 + if (!val) 152 + return count; 153 + 154 + pm_runtime_get_sync(&usb4->dev); 155 + 156 + if (mutex_lock_interruptible(&tb->lock)) { 157 + ret = -ERESTARTSYS; 158 + goto out_rpm; 159 + } 160 + 161 + /* Must be in offline mode already */ 162 + if (!usb4->offline) { 163 + ret = -EINVAL; 164 + goto out_unlock; 165 + } 166 + 167 + tb_retimer_remove_all(port); 168 + ret = tb_retimer_scan(port, true); 169 + 170 + out_unlock: 171 + mutex_unlock(&tb->lock); 172 + out_rpm: 173 + pm_runtime_mark_last_busy(&usb4->dev); 174 + pm_runtime_put_autosuspend(&usb4->dev); 175 + 176 + return ret ? ret : count; 177 + } 178 + static DEVICE_ATTR_WO(rescan); 179 + 180 + static struct attribute *service_attrs[] = { 181 + &dev_attr_offline.attr, 182 + &dev_attr_rescan.attr, 183 + NULL 184 + }; 185 + 186 + static umode_t service_attr_is_visible(struct kobject *kobj, 187 + struct attribute *attr, int n) 188 + { 189 + struct device *dev = kobj_to_dev(kobj); 190 + struct usb4_port *usb4 = tb_to_usb4_port_device(dev); 191 + 192 + /* 193 + * Always need some platform help to cycle the modes so that 194 + * retimers can be accessed through the sideband. 195 + */ 196 + return usb4->can_offline ? attr->mode : 0; 197 + } 198 + 199 + static const struct attribute_group service_group = { 200 + .attrs = service_attrs, 201 + .is_visible = service_attr_is_visible, 202 + }; 203 + 47 204 static const struct attribute_group *usb4_port_device_groups[] = { 48 205 &common_group, 206 + &service_group, 49 207 NULL 50 208 }; 51 209 ··· 267 109 void usb4_port_device_remove(struct usb4_port *usb4) 268 110 { 269 111 device_unregister(&usb4->dev); 112 + } 113 + 114 + /** 115 + * usb4_port_device_resume() - Resumes USB4 port device 116 + * @usb4: USB4 port device 117 + * 118 + * Used to resume USB4 port device after sleep state. 119 + */ 120 + int usb4_port_device_resume(struct usb4_port *usb4) 121 + { 122 + return usb4->offline ? usb4_port_offline(usb4) : 0; 270 123 }