// SPDX-License-Identifier: GPL-2.0/* * USB4 specific functionality * * Copyright (C) 2019, Intel Corporation * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Rajmohan Mani <rajmohan.mani@intel.com> */ #include <linux/delay.h>#include <linux/ktime.h>#include <linux/string_choices.h>#include <linux/units.h> #include "sb_regs.h"#include "tb.h" #define USB4_DATA_RETRIES 3#define USB4_DATA_DWORDS 16 #define USB4_NVM_READ_OFFSET_MASK GENMASK(23, 2)#define USB4_NVM_READ_OFFSET_SHIFT 2#define USB4_NVM_READ_LENGTH_MASK GENMASK(27, 24)#define USB4_NVM_READ_LENGTH_SHIFT 24 #define USB4_NVM_SET_OFFSET_MASK USB4_NVM_READ_OFFSET_MASK#define USB4_NVM_SET_OFFSET_SHIFT USB4_NVM_READ_OFFSET_SHIFT #define USB4_DROM_ADDRESS_MASK GENMASK(14, 2)#define USB4_DROM_ADDRESS_SHIFT 2#define USB4_DROM_SIZE_MASK GENMASK(19, 15)#define USB4_DROM_SIZE_SHIFT 15 #define USB4_NVM_SECTOR_SIZE_MASK GENMASK(23, 0) #define USB4_BA_LENGTH_MASK GENMASK(7, 0)#define USB4_BA_INDEX_MASK GENMASK(15, 0) enum usb4_ba_index { USB4_BA_MAX_USB3 = 0x1, USB4_BA_MIN_DP_AUX = 0x2, USB4_BA_MIN_DP_MAIN = 0x3, USB4_BA_MAX_PCIE = 0x4, USB4_BA_MAX_HI = 0x5,}; #define USB4_BA_VALUE_MASK GENMASK(31, 16)#define USB4_BA_VALUE_SHIFT 16 /* Delays in us used with usb4_port_wait_for_bit() */#define USB4_PORT_DELAY 50#define USB4_PORT_SB_DELAY 1000 static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, void *rx_data, size_t rx_dwords){ u32 val; int ret; if (metadata) { ret = tb_sw_write(sw, metadata, TB_CFG_SWITCH, ROUTER_CS_25, 1); if (ret) return ret; } if (tx_dwords) { ret = tb_sw_write(sw, tx_data, TB_CFG_SWITCH, ROUTER_CS_9, tx_dwords); if (ret) return ret; } val = opcode | ROUTER_CS_26_OV; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_26, 1); if (ret) return ret; ret = tb_switch_wait_for_bit(sw, ROUTER_CS_26, ROUTER_CS_26_OV, 0, 500); if (ret) return ret; ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_26, 1); if (ret) return ret; if (val & ROUTER_CS_26_ONS) return -EOPNOTSUPP; if (status) *status = (val & ROUTER_CS_26_STATUS_MASK) >> ROUTER_CS_26_STATUS_SHIFT; if (metadata) { ret = tb_sw_read(sw, metadata, TB_CFG_SWITCH, ROUTER_CS_25, 1); if (ret) return ret; } if (rx_dwords) { ret = tb_sw_read(sw, rx_data, TB_CFG_SWITCH, ROUTER_CS_9, rx_dwords); if (ret) return ret; } return 0;} static int __usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, void *rx_data, size_t rx_dwords){ const struct tb_cm_ops *cm_ops = sw->tb->cm_ops; if (tx_dwords > USB4_DATA_DWORDS || rx_dwords > USB4_DATA_DWORDS) return -EINVAL; /* * If the connection manager implementation provides USB4 router * operation proxy callback, call it here instead of running the * operation natively. */ if (cm_ops->usb4_switch_op) { int ret; ret = cm_ops->usb4_switch_op(sw, opcode, metadata, status, tx_data, tx_dwords, rx_data, rx_dwords); if (ret != -EOPNOTSUPP) return ret; /* * If the proxy was not supported then run the native * router operation instead. */ } return usb4_native_switch_op(sw, opcode, metadata, status, tx_data, tx_dwords, rx_data, rx_dwords);} static inline int usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status){ return __usb4_switch_op(sw, opcode, metadata, status, NULL, 0, NULL, 0);} static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, void *rx_data, size_t rx_dwords){ return __usb4_switch_op(sw, opcode, metadata, status, tx_data, tx_dwords, rx_data, rx_dwords);} /** * usb4_switch_check_wakes() - Check for wakes and notify PM core about them * @sw: Router whose wakes to check * * Checks wakes occurred during suspend and notify the PM core about them. */void usb4_switch_check_wakes(struct tb_switch *sw){ bool wakeup_usb4 = false; struct usb4_port *usb4; struct tb_port *port; bool wakeup = false; u32 val; if (tb_route(sw)) { if (tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_6, 1)) return; tb_sw_dbg(sw, "PCIe wake: %s, USB3 wake: %s\n", str_yes_no(val & ROUTER_CS_6_WOPS), str_yes_no(val & ROUTER_CS_6_WOUS)); wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS); } /* * Check for any downstream ports for USB4 wake, * connection wake and disconnection wake. */ tb_switch_for_each_port(sw, port) { if (!port->cap_usb4) continue; if (tb_port_read(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_18, 1)) break; tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n", str_yes_no(val & PORT_CS_18_WOU4S), str_yes_no(val & PORT_CS_18_WOCS), str_yes_no(val & PORT_CS_18_WODS)); wakeup_usb4 = val & (PORT_CS_18_WOU4S | PORT_CS_18_WOCS | PORT_CS_18_WODS); usb4 = port->usb4; if (device_may_wakeup(&usb4->dev) && wakeup_usb4) pm_wakeup_event(&usb4->dev, 0); wakeup |= wakeup_usb4; } if (wakeup) pm_wakeup_event(&sw->dev, 0);} static bool link_is_usb4(struct tb_port *port){ u32 val; if (!port->cap_usb4) return false; if (tb_port_read(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_18, 1)) return false; return !(val & PORT_CS_18_TCM);} /** * usb4_switch_setup() - Additional setup for USB4 device * @sw: USB4 router to setup * * USB4 routers need additional settings in order to enable all the * tunneling. This function enables USB and PCIe tunneling if it can be * enabled (e.g the parent switch also supports them). If USB tunneling * is not available for some reason (like that there is Thunderbolt 3 * switch upstream) then the internal xHCI controller is enabled * instead. * * This does not set the configuration valid bit of the router. To do * that call usb4_switch_configuration_valid(). * * Return: %0 on success, negative errno otherwise. */int usb4_switch_setup(struct tb_switch *sw){ struct tb_switch *parent = tb_switch_parent(sw); struct tb_port *down; bool tbt3, xhci; u32 val = 0; int ret; if (!tb_route(sw)) return 0; ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_6, 1); if (ret) return ret; down = tb_switch_downstream_port(sw); sw->link_usb4 = link_is_usb4(down); tb_sw_dbg(sw, "link: %s\n", sw->link_usb4 ? "USB4" : "TBT"); xhci = val & ROUTER_CS_6_HCI; tbt3 = !(val & ROUTER_CS_6_TNS); tb_sw_dbg(sw, "TBT3 support: %s, xHCI: %s\n", str_yes_no(tbt3), str_yes_no(xhci)); ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; if (tb_acpi_may_tunnel_usb3() && sw->link_usb4 && tb_switch_find_port(parent, TB_TYPE_USB3_DOWN)) { val |= ROUTER_CS_5_UTO; xhci = false; } /* * Only enable PCIe tunneling if the parent router supports it * and it is not disabled. */ if (tb_acpi_may_tunnel_pcie() && tb_switch_find_port(parent, TB_TYPE_PCIE_DOWN)) { val |= ROUTER_CS_5_PTO; /* * xHCI can be enabled if PCIe tunneling is supported * and the parent does not have any USB3 downstream * adapters (so we cannot do USB 3.x tunneling). */ if (xhci) val |= ROUTER_CS_5_HCO; } /* TBT3 supported by the CM */ val &= ~ROUTER_CS_5_CNS; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; return tb_switch_wait_for_bit(sw, ROUTER_CS_6, ROUTER_CS_6_RR, ROUTER_CS_6_RR, 500);} /** * usb4_switch_configuration_valid() - Set tunneling configuration to be valid * @sw: USB4 router * * Sets configuration valid bit for the router. Must be called before * any tunnels can be set through the router and after * usb4_switch_setup() has been called. Can be called to host and device * routers (does nothing for the former). * * Return: %0 on success, negative errno otherwise. */int usb4_switch_configuration_valid(struct tb_switch *sw){ u32 val; int ret; if (!tb_route(sw)) return 0; ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; val |= ROUTER_CS_5_CV; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; return tb_switch_wait_for_bit(sw, ROUTER_CS_6, ROUTER_CS_6_CR, ROUTER_CS_6_CR, 500);} /** * usb4_switch_read_uid() - Read UID from USB4 router * @sw: USB4 router * @uid: UID is stored here * * Reads 64-bit UID from USB4 router config space. * * Return: %0 on success, negative errno otherwise. */int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid){ return tb_sw_read(sw, uid, TB_CFG_SWITCH, ROUTER_CS_7, 2);} static int usb4_switch_drom_read_block(void *data, unsigned int dwaddress, void *buf, size_t dwords){ struct tb_switch *sw = data; u8 status = 0; u32 metadata; int ret; metadata = (dwords << USB4_DROM_SIZE_SHIFT) & USB4_DROM_SIZE_MASK; metadata |= (dwaddress << USB4_DROM_ADDRESS_SHIFT) & USB4_DROM_ADDRESS_MASK; ret = usb4_switch_op_data(sw, USB4_SWITCH_OP_DROM_READ, &metadata, &status, NULL, 0, buf, dwords); if (ret) return ret; return status ? -EIO : 0;} /** * usb4_switch_drom_read() - Read arbitrary bytes from USB4 router DROM * @sw: USB4 router * @address: Byte address inside DROM to start reading * @buf: Buffer where the DROM content is stored * @size: Number of bytes to read from DROM * * Uses USB4 router operations to read router DROM. For devices this * should always work but for hosts it may return %-EOPNOTSUPP in which * case the host router does not have DROM. * * Return: %0 on success, negative errno otherwise. */int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size){ return tb_nvm_read_data(address, buf, size, USB4_DATA_RETRIES, usb4_switch_drom_read_block, sw);} /** * usb4_switch_lane_bonding_possible() - Are conditions met for lane bonding * @sw: USB4 router * * Checks whether conditions are met so that lane bonding can be * established with the upstream router. Call only for device routers. * * Return: %true if lane bonding is possible, %false otherwise. */bool usb4_switch_lane_bonding_possible(struct tb_switch *sw){ struct tb_port *up; int ret; u32 val; up = tb_upstream_port(sw); ret = tb_port_read(up, &val, TB_CFG_PORT, up->cap_usb4 + PORT_CS_18, 1); if (ret) return false; return !!(val & PORT_CS_18_BE);} /** * usb4_switch_set_wake() - Enabled/disable wake * @sw: USB4 router * @flags: Wakeup flags (%0 to disable) * @runtime: Wake is being programmed during system runtime * * Enables/disables router to wake up from sleep. * * Return: %0 on success, negative errno otherwise. */int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime){ struct tb_port *port; u64 route = tb_route(sw); u32 val; int ret; /* * Enable wakes coming from all USB4 downstream ports (from * child routers). For device routers do this also for the * upstream USB4 port. */ tb_switch_for_each_port(sw, port) { if (!tb_port_is_null(port)) continue; if (!route && tb_is_upstream_port(port)) continue; if (!port->cap_usb4) continue; ret = tb_port_read(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_19, 1); if (ret) return ret; val &= ~(PORT_CS_19_WOC | PORT_CS_19_WOD | PORT_CS_19_WOU4); if (tb_is_upstream_port(port)) { val |= PORT_CS_19_WOU4; } else { bool configured = val & PORT_CS_19_PC; bool wakeup = runtime || device_may_wakeup(&port->usb4->dev); if ((flags & TB_WAKE_ON_CONNECT) && wakeup && !configured) val |= PORT_CS_19_WOC; if ((flags & TB_WAKE_ON_DISCONNECT) && wakeup && configured) val |= PORT_CS_19_WOD; if ((flags & TB_WAKE_ON_USB4) && configured) val |= PORT_CS_19_WOU4; } ret = tb_port_write(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_19, 1); if (ret) return ret; } /* * Enable wakes from PCIe, USB 3.x and DP on this router. Only * needed for device routers. */ if (route) { ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; val &= ~(ROUTER_CS_5_WOP | ROUTER_CS_5_WOU | ROUTER_CS_5_WOD); if (flags & TB_WAKE_ON_USB3) val |= ROUTER_CS_5_WOU; if (flags & TB_WAKE_ON_PCIE) val |= ROUTER_CS_5_WOP; if (flags & TB_WAKE_ON_DP) val |= ROUTER_CS_5_WOD; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; } return 0;} /** * usb4_switch_set_sleep() - Prepare the router to enter sleep * @sw: USB4 routerLines 1–500 of 3176. Load more
// SPDX-License-Identifier: GPL-2.0 /* * USB4 specific functionality * * Copyright (C) 2019, Intel Corporation * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Rajmohan Mani <rajmohan.mani@intel.com> */ #include <linux/delay.h> #include <linux/ktime.h> #include <linux/string_choices.h> #include <linux/units.h> #include "sb_regs.h" #include "tb.h" #define USB4_DATA_RETRIES 3 #define USB4_DATA_DWORDS 16 #define USB4_NVM_READ_OFFSET_MASK GENMASK(23, 2) #define USB4_NVM_READ_OFFSET_SHIFT 2 #define USB4_NVM_READ_LENGTH_MASK GENMASK(27, 24) #define USB4_NVM_READ_LENGTH_SHIFT 24 #define USB4_NVM_SET_OFFSET_MASK USB4_NVM_READ_OFFSET_MASK #define USB4_NVM_SET_OFFSET_SHIFT USB4_NVM_READ_OFFSET_SHIFT #define USB4_DROM_ADDRESS_MASK GENMASK(14, 2) #define USB4_DROM_ADDRESS_SHIFT 2 #define USB4_DROM_SIZE_MASK GENMASK(19, 15) #define USB4_DROM_SIZE_SHIFT 15 #define USB4_NVM_SECTOR_SIZE_MASK GENMASK(23, 0) #define USB4_BA_LENGTH_MASK GENMASK(7, 0) #define USB4_BA_INDEX_MASK GENMASK(15, 0) enum usb4_ba_index { USB4_BA_MAX_USB3 = 0x1, USB4_BA_MIN_DP_AUX = 0x2, USB4_BA_MIN_DP_MAIN = 0x3, USB4_BA_MAX_PCIE = 0x4, USB4_BA_MAX_HI = 0x5, }; #define USB4_BA_VALUE_MASK GENMASK(31, 16) #define USB4_BA_VALUE_SHIFT 16 /* Delays in us used with usb4_port_wait_for_bit() */ #define USB4_PORT_DELAY 50 #define USB4_PORT_SB_DELAY 1000 static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, void *rx_data, size_t rx_dwords) { u32 val; int ret; if (metadata) { ret = tb_sw_write(sw, metadata, TB_CFG_SWITCH, ROUTER_CS_25, 1); if (ret) return ret; } if (tx_dwords) { ret = tb_sw_write(sw, tx_data, TB_CFG_SWITCH, ROUTER_CS_9, tx_dwords); if (ret) return ret; } val = opcode | ROUTER_CS_26_OV; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_26, 1); if (ret) return ret; ret = tb_switch_wait_for_bit(sw, ROUTER_CS_26, ROUTER_CS_26_OV, 0, 500); if (ret) return ret; ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_26, 1); if (ret) return ret; if (val & ROUTER_CS_26_ONS) return -EOPNOTSUPP; if (status) *status = (val & ROUTER_CS_26_STATUS_MASK) >> ROUTER_CS_26_STATUS_SHIFT; if (metadata) { ret = tb_sw_read(sw, metadata, TB_CFG_SWITCH, ROUTER_CS_25, 1); if (ret) return ret; } if (rx_dwords) { ret = tb_sw_read(sw, rx_data, TB_CFG_SWITCH, ROUTER_CS_9, rx_dwords); if (ret) return ret; } return 0; } static int __usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, void *rx_data, size_t rx_dwords) { const struct tb_cm_ops *cm_ops = sw->tb->cm_ops; if (tx_dwords > USB4_DATA_DWORDS || rx_dwords > USB4_DATA_DWORDS) return -EINVAL; /* * If the connection manager implementation provides USB4 router * operation proxy callback, call it here instead of running the * operation natively. */ if (cm_ops->usb4_switch_op) { int ret; ret = cm_ops->usb4_switch_op(sw, opcode, metadata, status, tx_data, tx_dwords, rx_data, rx_dwords); if (ret != -EOPNOTSUPP) return ret; /* * If the proxy was not supported then run the native * router operation instead. */ } return usb4_native_switch_op(sw, opcode, metadata, status, tx_data, tx_dwords, rx_data, rx_dwords); } static inline int usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status) { return __usb4_switch_op(sw, opcode, metadata, status, NULL, 0, NULL, 0); } static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, void *rx_data, size_t rx_dwords) { return __usb4_switch_op(sw, opcode, metadata, status, tx_data, tx_dwords, rx_data, rx_dwords); } /** * usb4_switch_check_wakes() - Check for wakes and notify PM core about them * @sw: Router whose wakes to check * * Checks wakes occurred during suspend and notify the PM core about them. */ void usb4_switch_check_wakes(struct tb_switch *sw) { bool wakeup_usb4 = false; struct usb4_port *usb4; struct tb_port *port; bool wakeup = false; u32 val; if (tb_route(sw)) { if (tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_6, 1)) return; tb_sw_dbg(sw, "PCIe wake: %s, USB3 wake: %s\n", str_yes_no(val & ROUTER_CS_6_WOPS), str_yes_no(val & ROUTER_CS_6_WOUS)); wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS); } /* * Check for any downstream ports for USB4 wake, * connection wake and disconnection wake. */ tb_switch_for_each_port(sw, port) { if (!port->cap_usb4) continue; if (tb_port_read(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_18, 1)) break; tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n", str_yes_no(val & PORT_CS_18_WOU4S), str_yes_no(val & PORT_CS_18_WOCS), str_yes_no(val & PORT_CS_18_WODS)); wakeup_usb4 = val & (PORT_CS_18_WOU4S | PORT_CS_18_WOCS | PORT_CS_18_WODS); usb4 = port->usb4; if (device_may_wakeup(&usb4->dev) && wakeup_usb4) pm_wakeup_event(&usb4->dev, 0); wakeup |= wakeup_usb4; } if (wakeup) pm_wakeup_event(&sw->dev, 0); } static bool link_is_usb4(struct tb_port *port) { u32 val; if (!port->cap_usb4) return false; if (tb_port_read(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_18, 1)) return false; return !(val & PORT_CS_18_TCM); } /** * usb4_switch_setup() - Additional setup for USB4 device * @sw: USB4 router to setup * * USB4 routers need additional settings in order to enable all the * tunneling. This function enables USB and PCIe tunneling if it can be * enabled (e.g the parent switch also supports them). If USB tunneling * is not available for some reason (like that there is Thunderbolt 3 * switch upstream) then the internal xHCI controller is enabled * instead. * * This does not set the configuration valid bit of the router. To do * that call usb4_switch_configuration_valid(). * * Return: %0 on success, negative errno otherwise. */ int usb4_switch_setup(struct tb_switch *sw) { struct tb_switch *parent = tb_switch_parent(sw); struct tb_port *down; bool tbt3, xhci; u32 val = 0; int ret; if (!tb_route(sw)) return 0; ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_6, 1); if (ret) return ret; down = tb_switch_downstream_port(sw); sw->link_usb4 = link_is_usb4(down); tb_sw_dbg(sw, "link: %s\n", sw->link_usb4 ? "USB4" : "TBT"); xhci = val & ROUTER_CS_6_HCI; tbt3 = !(val & ROUTER_CS_6_TNS); tb_sw_dbg(sw, "TBT3 support: %s, xHCI: %s\n", str_yes_no(tbt3), str_yes_no(xhci)); ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; if (tb_acpi_may_tunnel_usb3() && sw->link_usb4 && tb_switch_find_port(parent, TB_TYPE_USB3_DOWN)) { val |= ROUTER_CS_5_UTO; xhci = false; } /* * Only enable PCIe tunneling if the parent router supports it * and it is not disabled. */ if (tb_acpi_may_tunnel_pcie() && tb_switch_find_port(parent, TB_TYPE_PCIE_DOWN)) { val |= ROUTER_CS_5_PTO; /* * xHCI can be enabled if PCIe tunneling is supported * and the parent does not have any USB3 downstream * adapters (so we cannot do USB 3.x tunneling). */ if (xhci) val |= ROUTER_CS_5_HCO; } /* TBT3 supported by the CM */ val &= ~ROUTER_CS_5_CNS; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; return tb_switch_wait_for_bit(sw, ROUTER_CS_6, ROUTER_CS_6_RR, ROUTER_CS_6_RR, 500); } /** * usb4_switch_configuration_valid() - Set tunneling configuration to be valid * @sw: USB4 router * * Sets configuration valid bit for the router. Must be called before * any tunnels can be set through the router and after * usb4_switch_setup() has been called. Can be called to host and device * routers (does nothing for the former). * * Return: %0 on success, negative errno otherwise. */ int usb4_switch_configuration_valid(struct tb_switch *sw) { u32 val; int ret; if (!tb_route(sw)) return 0; ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; val |= ROUTER_CS_5_CV; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; return tb_switch_wait_for_bit(sw, ROUTER_CS_6, ROUTER_CS_6_CR, ROUTER_CS_6_CR, 500); } /** * usb4_switch_read_uid() - Read UID from USB4 router * @sw: USB4 router * @uid: UID is stored here * * Reads 64-bit UID from USB4 router config space. * * Return: %0 on success, negative errno otherwise. */ int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid) { return tb_sw_read(sw, uid, TB_CFG_SWITCH, ROUTER_CS_7, 2); } static int usb4_switch_drom_read_block(void *data, unsigned int dwaddress, void *buf, size_t dwords) { struct tb_switch *sw = data; u8 status = 0; u32 metadata; int ret; metadata = (dwords << USB4_DROM_SIZE_SHIFT) & USB4_DROM_SIZE_MASK; metadata |= (dwaddress << USB4_DROM_ADDRESS_SHIFT) & USB4_DROM_ADDRESS_MASK; ret = usb4_switch_op_data(sw, USB4_SWITCH_OP_DROM_READ, &metadata, &status, NULL, 0, buf, dwords); if (ret) return ret; return status ? -EIO : 0; } /** * usb4_switch_drom_read() - Read arbitrary bytes from USB4 router DROM * @sw: USB4 router * @address: Byte address inside DROM to start reading * @buf: Buffer where the DROM content is stored * @size: Number of bytes to read from DROM * * Uses USB4 router operations to read router DROM. For devices this * should always work but for hosts it may return %-EOPNOTSUPP in which * case the host router does not have DROM. * * Return: %0 on success, negative errno otherwise. */ int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) { return tb_nvm_read_data(address, buf, size, USB4_DATA_RETRIES, usb4_switch_drom_read_block, sw); } /** * usb4_switch_lane_bonding_possible() - Are conditions met for lane bonding * @sw: USB4 router * * Checks whether conditions are met so that lane bonding can be * established with the upstream router. Call only for device routers. * * Return: %true if lane bonding is possible, %false otherwise. */ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw) { struct tb_port *up; int ret; u32 val; up = tb_upstream_port(sw); ret = tb_port_read(up, &val, TB_CFG_PORT, up->cap_usb4 + PORT_CS_18, 1); if (ret) return false; return !!(val & PORT_CS_18_BE); } /** * usb4_switch_set_wake() - Enabled/disable wake * @sw: USB4 router * @flags: Wakeup flags (%0 to disable) * @runtime: Wake is being programmed during system runtime * * Enables/disables router to wake up from sleep. * * Return: %0 on success, negative errno otherwise. */ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime) { struct tb_port *port; u64 route = tb_route(sw); u32 val; int ret; /* * Enable wakes coming from all USB4 downstream ports (from * child routers). For device routers do this also for the * upstream USB4 port. */ tb_switch_for_each_port(sw, port) { if (!tb_port_is_null(port)) continue; if (!route && tb_is_upstream_port(port)) continue; if (!port->cap_usb4) continue; ret = tb_port_read(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_19, 1); if (ret) return ret; val &= ~(PORT_CS_19_WOC | PORT_CS_19_WOD | PORT_CS_19_WOU4); if (tb_is_upstream_port(port)) { val |= PORT_CS_19_WOU4; } else { bool configured = val & PORT_CS_19_PC; bool wakeup = runtime || device_may_wakeup(&port->usb4->dev); if ((flags & TB_WAKE_ON_CONNECT) && wakeup && !configured) val |= PORT_CS_19_WOC; if ((flags & TB_WAKE_ON_DISCONNECT) && wakeup && configured) val |= PORT_CS_19_WOD; if ((flags & TB_WAKE_ON_USB4) && configured) val |= PORT_CS_19_WOU4; } ret = tb_port_write(port, &val, TB_CFG_PORT, port->cap_usb4 + PORT_CS_19, 1); if (ret) return ret; } /* * Enable wakes from PCIe, USB 3.x and DP on this router. Only * needed for device routers. */ if (route) { ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; val &= ~(ROUTER_CS_5_WOP | ROUTER_CS_5_WOU | ROUTER_CS_5_WOD); if (flags & TB_WAKE_ON_USB3) val |= ROUTER_CS_5_WOU; if (flags & TB_WAKE_ON_PCIE) val |= ROUTER_CS_5_WOP; if (flags & TB_WAKE_ON_DP) val |= ROUTER_CS_5_WOD; ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1); if (ret) return ret; } return 0; } /** * usb4_switch_set_sleep() - Prepare the router to enter sleep * @sw: USB4 router