summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/usb4.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thunderbolt/usb4.c')
-rw-r--r--drivers/thunderbolt/usb4.c826
1 files changed, 555 insertions, 271 deletions
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 05ddb224c464..9e810b2ae0b5 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/ktime.h>
+#include <linux/string_choices.h>
#include <linux/units.h>
#include "sb_regs.h"
@@ -17,12 +18,6 @@
#define USB4_DATA_RETRIES 3
#define USB4_DATA_DWORDS 16
-enum usb4_sb_target {
- USB4_SB_TARGET_ROUTER,
- USB4_SB_TARGET_PARTNER,
- USB4_SB_TARGET_RETIMER,
-};
-
#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)
@@ -52,6 +47,10 @@ enum usb4_ba_index {
#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,
@@ -155,7 +154,13 @@ static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode,
tx_dwords, rx_data, rx_dwords);
}
-static void usb4_switch_check_wakes(struct tb_switch *sw)
+/**
+ * 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;
@@ -163,16 +168,13 @@ static void usb4_switch_check_wakes(struct tb_switch *sw)
bool wakeup = false;
u32 val;
- if (!device_may_wakeup(&sw->dev))
- return;
-
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",
- (val & ROUTER_CS_6_WOPS) ? "yes" : "no",
- (val & ROUTER_CS_6_WOUS) ? "yes" : "no");
+ 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);
}
@@ -190,9 +192,9 @@ static void usb4_switch_check_wakes(struct tb_switch *sw)
break;
tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n",
- (val & PORT_CS_18_WOU4S) ? "yes" : "no",
- (val & PORT_CS_18_WOCS) ? "yes" : "no",
- (val & PORT_CS_18_WODS) ? "yes" : "no");
+ 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);
@@ -235,6 +237,8 @@ static bool link_is_usb4(struct tb_port *port)
*
* 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)
{
@@ -244,8 +248,6 @@ int usb4_switch_setup(struct tb_switch *sw)
u32 val = 0;
int ret;
- usb4_switch_check_wakes(sw);
-
if (!tb_route(sw))
return 0;
@@ -261,7 +263,7 @@ int usb4_switch_setup(struct tb_switch *sw)
tbt3 = !(val & ROUTER_CS_6_TNS);
tb_sw_dbg(sw, "TBT3 support: %s, xHCI: %s\n",
- tbt3 ? "yes" : "no", xhci ? "yes" : "no");
+ str_yes_no(tbt3), str_yes_no(xhci));
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1);
if (ret)
@@ -282,7 +284,7 @@ int usb4_switch_setup(struct tb_switch *sw)
val |= ROUTER_CS_5_PTO;
/*
* xHCI can be enabled if PCIe tunneling is supported
- * and the parent does not have any USB3 dowstream
+ * and the parent does not have any USB3 downstream
* adapters (so we cannot do USB 3.x tunneling).
*/
if (xhci)
@@ -290,7 +292,7 @@ int usb4_switch_setup(struct tb_switch *sw)
}
/* TBT3 supported by the CM */
- val |= ROUTER_CS_5_C3S;
+ val &= ~ROUTER_CS_5_CNS;
return tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1);
}
@@ -304,7 +306,7 @@ int usb4_switch_setup(struct tb_switch *sw)
* usb4_switch_setup() has been called. Can be called to host and device
* routers (does nothing for the latter).
*
- * Returns %0 in success and negative errno otherwise.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_configuration_valid(struct tb_switch *sw)
{
@@ -334,6 +336,8 @@ int usb4_switch_configuration_valid(struct tb_switch *sw)
* @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)
{
@@ -371,6 +375,8 @@ static int usb4_switch_drom_read_block(void *data,
* 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)
@@ -385,6 +391,8 @@ int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf,
*
* 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)
{
@@ -404,12 +412,14 @@ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw)
* 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)
+int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags, bool runtime)
{
- struct usb4_port *usb4;
struct tb_port *port;
u64 route = tb_route(sw);
u32 val;
@@ -439,13 +449,11 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
val |= PORT_CS_19_WOU4;
} else {
bool configured = val & PORT_CS_19_PC;
- usb4 = port->usb4;
+ bool wakeup = runtime || device_may_wakeup(&port->usb4->dev);
- if (((flags & TB_WAKE_ON_CONNECT) |
- device_may_wakeup(&usb4->dev)) && !configured)
+ if ((flags & TB_WAKE_ON_CONNECT) && wakeup && !configured)
val |= PORT_CS_19_WOC;
- if (((flags & TB_WAKE_ON_DISCONNECT) |
- device_may_wakeup(&usb4->dev)) && configured)
+ 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;
@@ -486,8 +494,10 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
* usb4_switch_set_sleep() - Prepare the router to enter sleep
* @sw: USB4 router
*
- * Sets sleep bit for the router. Returns when the router sleep ready
+ * Sets sleep bit for the router and waits until router sleep ready
* bit has been asserted.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_set_sleep(struct tb_switch *sw)
{
@@ -513,9 +523,10 @@ int usb4_switch_set_sleep(struct tb_switch *sw)
* usb4_switch_nvm_sector_size() - Return router NVM sector size
* @sw: USB4 router
*
- * If the router supports NVM operations this function returns the NVM
- * sector size in bytes. If NVM operations are not supported returns
- * %-EOPNOTSUPP.
+ * Return:
+ * * NVM sector size in bytes if router supports NVM operations.
+ * * %-EOPNOTSUPP - If router does not support NVM operations.
+ * * Negative errno - Another error occurred.
*/
int usb4_switch_nvm_sector_size(struct tb_switch *sw)
{
@@ -562,8 +573,12 @@ static int usb4_switch_nvm_read_block(void *data,
* @buf: Read data is placed here
* @size: How many bytes to read
*
- * Reads NVM contents of the router. If NVM is not supported returns
- * %-EOPNOTSUPP.
+ * Reads NVM contents of the router.
+ *
+ * Return:
+ * * %0 - Read completed successfully.
+ * * %-EOPNOTSUPP - NVM not supported.
+ * * Negative errno - Another error occurred.
*/
int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
size_t size)
@@ -580,7 +595,7 @@ int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
* Explicitly sets NVM write offset. Normally when writing to NVM this
* is done automatically by usb4_switch_nvm_write().
*
- * Returns %0 in success and negative errno if there was a failure.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_nvm_set_offset(struct tb_switch *sw, unsigned int address)
{
@@ -622,8 +637,12 @@ static int usb4_switch_nvm_write_next_block(void *data, unsigned int dwaddress,
* @buf: Pointer to the data to write
* @size: Size of @buf in bytes
*
- * Writes @buf to the router NVM using USB4 router operations. If NVM
- * write is not supported returns %-EOPNOTSUPP.
+ * Writes @buf to the router NVM using USB4 router operations.
+ *
+ * Return:
+ * * %0 - Write completed successfully.
+ * * %-EOPNOTSUPP - NVM write not supported.
+ * * Negative errno - Another error occurred.
*/
int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address,
const void *buf, size_t size)
@@ -645,11 +664,13 @@ int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address,
* After the new NVM has been written via usb4_switch_nvm_write(), this
* function triggers NVM authentication process. The router gets power
* cycled and if the authentication is successful the new NVM starts
- * running. In case of failure returns negative errno.
+ * running.
*
* The caller should call usb4_switch_nvm_authenticate_status() to read
* the status of the authentication after power cycle. It should be the
* first router operation to avoid the status being lost.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_nvm_authenticate(struct tb_switch *sw)
{
@@ -677,11 +698,13 @@ int usb4_switch_nvm_authenticate(struct tb_switch *sw)
* @status: Status code of the operation
*
* The function checks if there is status available from the last NVM
- * authenticate router operation. If there is status then %0 is returned
- * and the status code is placed in @status. Returns negative errno in case
- * of failure.
+ * authenticate router operation.
*
* Must be called before any other router operation.
+ *
+ * Return:
+ * * %0 - If there is status. Status code is placed in @status.
+ * * Negative errno - Failure occurred.
*/
int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status)
{
@@ -725,7 +748,7 @@ int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status)
* allocation fields accordingly. Specifically @sw->credits_allocation
* is set to %true if these parameters can be used in tunneling.
*
- * Returns %0 on success and negative errno otherwise.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_credits_init(struct tb_switch *sw)
{
@@ -864,8 +887,10 @@ err_invalid:
* @in: DP IN adapter
*
* For DP tunneling this function can be used to query availability of
- * DP IN resource. Returns true if the resource is available for DP
- * tunneling, false otherwise.
+ * DP IN resource.
+ *
+ * Return: %true if the resource is available for DP tunneling, %false
+ * otherwise.
*/
bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in)
{
@@ -893,9 +918,12 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in)
* @in: DP IN adapter
*
* Allocates DP IN resource for DP tunneling using USB4 router
- * operations. If the resource was allocated returns %0. Otherwise
- * returns negative errno, in particular %-EBUSY if the resource is
- * already allocated.
+ * operations.
+ *
+ * Return:
+ * * %0 - Resource allocated successfully.
+ * * %-EBUSY - Resource is already allocated.
+ * * Negative errno - Other failure occurred.
*/
int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
{
@@ -919,6 +947,8 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
* @in: DP IN adapter
*
* Releases the previously allocated DP IN resource.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
{
@@ -936,7 +966,15 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
return status ? -EIO : 0;
}
-static int usb4_port_idx(const struct tb_switch *sw, const struct tb_port *port)
+/**
+ * usb4_port_index() - Finds matching USB4 port index
+ * @sw: USB4 router
+ * @port: USB4 protocol or lane adapter
+ *
+ * Finds matching USB4 port index (starting from %0) that given @port goes
+ * through.
+ */
+int usb4_port_index(const struct tb_switch *sw, const struct tb_port *port)
{
struct tb_port *p;
int usb4_idx = 0;
@@ -966,11 +1004,13 @@ static int usb4_port_idx(const struct tb_switch *sw, const struct tb_port *port)
* downstream adapters where the PCIe topology is extended. This
* function returns the corresponding downstream PCIe adapter or %NULL
* if no such mapping was possible.
+ *
+ * Return: Pointer to &struct tb_port or %NULL if not found.
*/
struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
const struct tb_port *port)
{
- int usb4_idx = usb4_port_idx(sw, port);
+ int usb4_idx = usb4_port_index(sw, port);
struct tb_port *p;
int pcie_idx = 0;
@@ -997,11 +1037,13 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
* downstream adapters where the USB 3.x topology is extended. This
* function returns the corresponding downstream USB 3.x adapter or
* %NULL if no such mapping was possible.
+ *
+ * Return: Pointer to &struct tb_port or %NULL if not found.
*/
struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw,
const struct tb_port *port)
{
- int usb4_idx = usb4_port_idx(sw, port);
+ int usb4_idx = usb4_port_index(sw, port);
struct tb_port *p;
int usb_idx = 0;
@@ -1026,7 +1068,7 @@ struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw,
* For USB4 router finds all USB4 ports and registers devices for each.
* Can be called to any router.
*
- * Return %0 in case of success and negative errno in case of failure.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_switch_add_ports(struct tb_switch *sw)
{
@@ -1079,6 +1121,8 @@ void usb4_switch_remove_ports(struct tb_switch *sw)
*
* Unlocks USB4 downstream port so that the connection manager can
* access the router below this port.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_unlock(struct tb_port *port)
{
@@ -1099,6 +1143,8 @@ int usb4_port_unlock(struct tb_port *port)
*
* Enables hot plug events on a given port. This is only intended
* to be used on lane, DP-IN, and DP-OUT adapters.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_hotplug_enable(struct tb_port *port)
{
@@ -1113,6 +1159,47 @@ int usb4_port_hotplug_enable(struct tb_port *port)
return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
}
+/**
+ * usb4_port_reset() - Issue downstream port reset
+ * @port: USB4 port to reset
+ *
+ * Issues downstream port reset to @port.
+ *
+ * Return: %0 on success, negative errno otherwise.
+ */
+int usb4_port_reset(struct tb_port *port)
+{
+ int ret;
+ u32 val;
+
+ if (!port->cap_usb4)
+ return -EINVAL;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_usb4 + PORT_CS_19, 1);
+ if (ret)
+ return ret;
+
+ val |= PORT_CS_19_DPR;
+
+ ret = tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_usb4 + PORT_CS_19, 1);
+ if (ret)
+ return ret;
+
+ fsleep(10000);
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_usb4 + PORT_CS_19, 1);
+ if (ret)
+ return ret;
+
+ val &= ~PORT_CS_19_DPR;
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_usb4 + PORT_CS_19, 1);
+}
+
static int usb4_port_set_configured(struct tb_port *port, bool configured)
{
int ret;
@@ -1140,6 +1227,8 @@ static int usb4_port_set_configured(struct tb_port *port, bool configured)
* @port: USB4 router
*
* Sets the USB4 link to be configured for power management purposes.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_configure(struct tb_port *port)
{
@@ -1151,6 +1240,8 @@ int usb4_port_configure(struct tb_port *port)
* @port: USB4 router
*
* Sets the USB4 link to be unconfigured for power management purposes.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
void usb4_port_unconfigure(struct tb_port *port)
{
@@ -1185,7 +1276,9 @@ static int usb4_set_xdomain_configured(struct tb_port *port, bool configured)
* @xd: XDomain that is connected to the port
*
* Marks the USB4 port as being connected to another host and updates
- * the link type. Returns %0 in success and negative errno in failure.
+ * the link type.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd)
{
@@ -1205,7 +1298,7 @@ void usb4_port_unconfigure_xdomain(struct tb_port *port)
}
static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit,
- u32 value, int timeout_msec)
+ u32 value, int timeout_msec, unsigned long delay_usec)
{
ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec);
@@ -1220,7 +1313,7 @@ static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit,
if ((val & bit) == value)
return 0;
- usleep_range(50, 100);
+ fsleep(delay_usec);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
@@ -1245,8 +1338,21 @@ static int usb4_port_write_data(struct tb_port *port, const void *data,
dwords);
}
-static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target,
- u8 index, u8 reg, void *buf, u8 size)
+/**
+ * usb4_port_sb_read() - Read from sideband register
+ * @port: USB4 port to read
+ * @target: Sideband target
+ * @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
+ * @reg: Sideband register index
+ * @buf: Buffer where the sideband data is copied
+ * @size: Size of @buf
+ *
+ * Reads data from sideband register @reg and copies it into @buf.
+ *
+ * Return: %0 on success, negative errno otherwise.
+ */
+int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index,
+ u8 reg, void *buf, u8 size)
{
size_t dwords = DIV_ROUND_UP(size, 4);
int ret;
@@ -1268,7 +1374,7 @@ static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target,
return ret;
ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1,
- PORT_CS_1_PND, 0, 500);
+ PORT_CS_1_PND, 0, 500, USB4_PORT_SB_DELAY);
if (ret)
return ret;
@@ -1285,8 +1391,21 @@ static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target,
return buf ? usb4_port_read_data(port, buf, dwords) : 0;
}
-static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
- u8 index, u8 reg, const void *buf, u8 size)
+/**
+ * usb4_port_sb_write() - Write to sideband register
+ * @port: USB4 port to write
+ * @target: Sideband target
+ * @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
+ * @reg: Sideband register index
+ * @buf: Data to write
+ * @size: Size of @buf
+ *
+ * Writes @buf to sideband register @reg.
+ *
+ * Return: %0 on success, negative errno otherwise.
+ */
+int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
+ u8 index, u8 reg, const void *buf, u8 size)
{
size_t dwords = DIV_ROUND_UP(size, 4);
int ret;
@@ -1315,7 +1434,7 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
return ret;
ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1,
- PORT_CS_1_PND, 0, 500);
+ PORT_CS_1_PND, 0, 500, USB4_PORT_SB_DELAY);
if (ret)
return ret;
@@ -1370,6 +1489,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
if (val != opcode)
return usb4_port_sb_opcode_err_to_errno(val);
+
+ fsleep(USB4_PORT_SB_DELAY);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
@@ -1398,8 +1519,7 @@ static int usb4_port_set_router_offline(struct tb_port *port, bool offline)
* port does not react on hotplug events anymore. This needs to be
* called before retimer access is done when the USB4 links is not up.
*
- * Returns %0 in case of success and negative errno if there was an
- * error.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_router_offline(struct tb_port *port)
{
@@ -1407,10 +1527,12 @@ int usb4_port_router_offline(struct tb_port *port)
}
/**
- * usb4_port_router_online() - Put the USB4 port back to online
+ * usb4_port_router_online() - Put the USB4 port back online
* @port: USB4 port
*
* Makes the USB4 port functional again.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_router_online(struct tb_port *port)
{
@@ -1422,8 +1544,9 @@ int usb4_port_router_online(struct tb_port *port)
* @port: USB4 port
*
* This forces the USB4 port to send broadcast RT transaction which
- * makes the retimers on the link to assign index to themselves. Returns
- * %0 in case of success and negative errno if there was an error.
+ * makes the retimers on the link assign index to themselves.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_enumerate_retimers(struct tb_port *port)
{
@@ -1440,6 +1563,8 @@ int usb4_port_enumerate_retimers(struct tb_port *port)
*
* PORT_CS_18_CPS bit reflects if the link supports CLx including
* active cables (if connected on the link).
+ *
+ * Return: %true if Clx is supported, %false otherwise.
*/
bool usb4_port_clx_supported(struct tb_port *port)
{
@@ -1455,123 +1580,264 @@ bool usb4_port_clx_supported(struct tb_port *port)
}
/**
- * usb4_port_margining_caps() - Read USB4 port marginig capabilities
+ * usb4_port_asym_supported() - If the port supports asymmetric link
+ * @port: USB4 port
+ *
+ * Checks if the port and the cable support asymmetric link.
+ *
+ * Return: %true if asymmetric link is supported, %false otherwise.
+ */
+bool usb4_port_asym_supported(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_CSA);
+}
+
+/**
+ * usb4_port_asym_set_link_width() - Set link width to asymmetric or symmetric
+ * @port: USB4 port
+ * @width: Asymmetric width to configure
+ *
+ * Sets USB4 port link width to @width. Can be called for widths where
+ * usb4_port_asym_width_supported() returned @true.
+ *
+ * Return: %0 on success, negative errno otherwise.
+ */
+int usb4_port_asym_set_link_width(struct tb_port *port, enum tb_link_width width)
+{
+ u32 val;
+ int ret;
+
+ if (!port->cap_phy)
+ return -EINVAL;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_phy + LANE_ADP_CS_1, 1);
+ if (ret)
+ return ret;
+
+ val &= ~LANE_ADP_CS_1_TARGET_WIDTH_ASYM_MASK;
+ switch (width) {
+ case TB_LINK_WIDTH_DUAL:
+ val |= FIELD_PREP(LANE_ADP_CS_1_TARGET_WIDTH_ASYM_MASK,
+ LANE_ADP_CS_1_TARGET_WIDTH_ASYM_DUAL);
+ break;
+ case TB_LINK_WIDTH_ASYM_TX:
+ val |= FIELD_PREP(LANE_ADP_CS_1_TARGET_WIDTH_ASYM_MASK,
+ LANE_ADP_CS_1_TARGET_WIDTH_ASYM_TX);
+ break;
+ case TB_LINK_WIDTH_ASYM_RX:
+ val |= FIELD_PREP(LANE_ADP_CS_1_TARGET_WIDTH_ASYM_MASK,
+ LANE_ADP_CS_1_TARGET_WIDTH_ASYM_RX);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_phy + LANE_ADP_CS_1, 1);
+}
+
+/**
+ * usb4_port_asym_start() - Start symmetry change and wait for completion
+ * @port: USB4 port
+ *
+ * Start symmetry change of the link to asymmetric or symmetric
+ * (according to what was previously set in tb_port_set_link_width().
+ * Wait for completion of the change.
+ *
+ * Return:
+ * * %0 - Symmetry change was successful.
+ * * %-ETIMEDOUT - Timeout occurred.
+ * * Negative errno - Other failure occurred.
+ */
+int usb4_port_asym_start(struct tb_port *port)
+{
+ int ret;
+ u32 val;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_usb4 + PORT_CS_19, 1);
+ if (ret)
+ return ret;
+
+ val &= ~PORT_CS_19_START_ASYM;
+ val |= FIELD_PREP(PORT_CS_19_START_ASYM, 1);
+
+ ret = tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_usb4 + PORT_CS_19, 1);
+ if (ret)
+ return ret;
+
+ /*
+ * Wait for PORT_CS_19_START_ASYM to be 0. This means the USB4
+ * port started the symmetry transition.
+ */
+ ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_19,
+ PORT_CS_19_START_ASYM, 0, 1000,
+ USB4_PORT_DELAY);
+ if (ret)
+ return ret;
+
+ /* Then wait for the transtion to be completed */
+ return usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_18,
+ PORT_CS_18_TIP, 0, 5000, USB4_PORT_DELAY);
+}
+
+/**
+ * usb4_port_margining_caps() - Read USB4 port margining capabilities
* @port: USB4 port
+ * @target: Sideband target
+ * @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
* @caps: Array with at least two elements to hold the results
+ * @ncaps: Number of elements in the caps array
*
* Reads the USB4 port lane margining capabilities into @caps.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
-int usb4_port_margining_caps(struct tb_port *port, u32 *caps)
+int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
+ u8 index, u32 *caps, size_t ncaps)
{
int ret;
- ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+ ret = usb4_port_sb_op(port, target, index,
USB4_SB_OPCODE_READ_LANE_MARGINING_CAP, 500);
if (ret)
return ret;
- return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
- USB4_SB_DATA, caps, sizeof(*caps) * 2);
+ return usb4_port_sb_read(port, target, index, USB4_SB_DATA, caps,
+ sizeof(*caps) * ncaps);
}
/**
* usb4_port_hw_margin() - Run hardware lane margining on port
* @port: USB4 port
- * @lanes: Which lanes to run (must match the port capabilities). Can be
- * %0, %1 or %7.
- * @ber_level: BER level contour value
- * @timing: Perform timing margining instead of voltage
- * @right_high: Use Right/high margin instead of left/low
- * @results: Array with at least two elements to hold the results
+ * @target: Sideband target
+ * @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
+ * @params: Parameters for USB4 hardware margining
+ * @results: Array to hold the results
+ * @nresults: Number of elements in the results array
*
* Runs hardware lane margining on USB4 port and returns the result in
* @results.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
-int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes,
- unsigned int ber_level, bool timing, bool right_high,
- u32 *results)
+int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
+ u8 index, const struct usb4_port_margining_params *params,
+ u32 *results, size_t nresults)
{
u32 val;
int ret;
- val = lanes;
- if (timing)
- val |= USB4_MARGIN_HW_TIME;
- if (right_high)
- val |= USB4_MARGIN_HW_RH;
- if (ber_level)
- val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) &
- USB4_MARGIN_HW_BER_MASK;
+ if (WARN_ON_ONCE(!params))
+ return -EINVAL;
- ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
- USB4_SB_METADATA, &val, sizeof(val));
+ val = params->lanes;
+ if (params->time)
+ val |= USB4_MARGIN_HW_TIME;
+ if (params->right_high || params->upper_eye)
+ val |= USB4_MARGIN_HW_RHU;
+ if (params->ber_level)
+ val |= FIELD_PREP(USB4_MARGIN_HW_BER_MASK, params->ber_level);
+ if (params->optional_voltage_offset_range)
+ val |= USB4_MARGIN_HW_OPT_VOLTAGE;
+
+ ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val,
+ sizeof(val));
if (ret)
return ret;
- ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+ ret = usb4_port_sb_op(port, target, index,
USB4_SB_OPCODE_RUN_HW_LANE_MARGINING, 2500);
if (ret)
return ret;
- return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
- USB4_SB_DATA, results, sizeof(*results) * 2);
+ return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results,
+ sizeof(*results) * nresults);
}
/**
* usb4_port_sw_margin() - Run software lane margining on port
* @port: USB4 port
- * @lanes: Which lanes to run (must match the port capabilities). Can be
- * %0, %1 or %7.
- * @timing: Perform timing margining instead of voltage
- * @right_high: Use Right/high margin instead of left/low
- * @counter: What to do with the error counter
+ * @target: Sideband target
+ * @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
+ * @params: Parameters for USB4 software margining
+ * @results: Data word for the operation completion data
*
* Runs software lane margining on USB4 port. Read back the error
- * counters by calling usb4_port_sw_margin_errors(). Returns %0 in
- * success and negative errno otherwise.
+ * counters by calling usb4_port_sw_margin_errors().
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
-int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
- bool right_high, u32 counter)
+int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
+ u8 index, const struct usb4_port_margining_params *params,
+ u32 *results)
{
u32 val;
int ret;
- val = lanes;
- if (timing)
+ if (WARN_ON_ONCE(!params))
+ return -EINVAL;
+
+ val = params->lanes;
+ if (params->time)
val |= USB4_MARGIN_SW_TIME;
- if (right_high)
+ if (params->optional_voltage_offset_range)
+ val |= USB4_MARGIN_SW_OPT_VOLTAGE;
+ if (params->right_high)
val |= USB4_MARGIN_SW_RH;
- val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) &
- USB4_MARGIN_SW_COUNTER_MASK;
+ if (params->upper_eye)
+ val |= USB4_MARGIN_SW_UPPER_EYE;
+ val |= FIELD_PREP(USB4_MARGIN_SW_COUNTER_MASK, params->error_counter);
+ val |= FIELD_PREP(USB4_MARGIN_SW_VT_MASK, params->voltage_time_offset);
- ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
- USB4_SB_METADATA, &val, sizeof(val));
+ ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val,
+ sizeof(val));
if (ret)
return ret;
- return usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
- USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500);
+ ret = usb4_port_sb_op(port, target, index,
+ USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500);
+ if (ret)
+ return ret;
+
+ return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results,
+ sizeof(*results));
+
}
/**
* usb4_port_sw_margin_errors() - Read the software margining error counters
* @port: USB4 port
+ * @target: Sideband target
+ * @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
* @errors: Error metadata is copied here.
*
* This reads back the software margining error counters from the port.
- * Returns %0 in success and negative errno otherwise.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
-int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors)
+int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
+ u8 index, u32 *errors)
{
int ret;
- ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0,
+ ret = usb4_port_sb_op(port, target, index,
USB4_SB_OPCODE_READ_SW_MARGIN_ERR, 150);
if (ret)
return ret;
- return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0,
- USB4_SB_METADATA, errors, sizeof(*errors));
+ return usb4_port_sb_read(port, target, index, USB4_SB_METADATA, errors,
+ sizeof(*errors));
}
static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
@@ -1587,8 +1853,10 @@ static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
* @port: USB4 port
* @index: Retimer index
*
- * Enables sideband channel transations on SBTX. Can be used when USB4
+ * Enables sideband channel transactions on SBTX. Can be used when USB4
* link does not go up, for example if there is no device connected.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index)
{
@@ -1614,8 +1882,10 @@ int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index)
* @port: USB4 port
* @index: Retimer index
*
- * Disables sideband channel transations on SBTX. The reverse of
+ * Disables sideband channel transactions on SBTX. The reverse of
* usb4_port_retimer_set_inbound_sbtx().
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index)
{
@@ -1624,68 +1894,55 @@ int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index)
}
/**
- * usb4_port_retimer_read() - Read from retimer sideband registers
+ * usb4_port_retimer_is_last() - Is the retimer last on-board retimer
* @port: USB4 port
* @index: Retimer index
- * @reg: Sideband register to read
- * @buf: Data from @reg is stored here
- * @size: Number of bytes to read
*
- * Function reads retimer sideband registers starting from @reg. The
- * retimer is connected to @port at @index. Returns %0 in case of
- * success, and read data is copied to @buf. If there is no retimer
- * present at given @index returns %-ENODEV. In any other failure
- * returns negative errno.
+ * Return:
+ * * %1 - Retimer at @index is the last one (connected directly to the
+ * Type-C port).
+ * * %0 - Retimer at @index is not the last one.
+ * * %-ENODEV - Retimer is not present.
+ * * Negative errno - Other failure occurred.
*/
-int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
- u8 size)
+int usb4_port_retimer_is_last(struct tb_port *port, u8 index)
{
- return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, reg, buf,
- size);
-}
+ u32 metadata;
+ int ret;
-/**
- * usb4_port_retimer_write() - Write to retimer sideband registers
- * @port: USB4 port
- * @index: Retimer index
- * @reg: Sideband register to write
- * @buf: Data that is written starting from @reg
- * @size: Number of bytes to write
- *
- * Writes retimer sideband registers starting from @reg. The retimer is
- * connected to @port at @index. Returns %0 in case of success. If there
- * is no retimer present at given @index returns %-ENODEV. In any other
- * failure returns negative errno.
- */
-int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,
- const void *buf, u8 size)
-{
- return usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, reg, buf,
- size);
+ ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_LAST_RETIMER,
+ 500);
+ if (ret)
+ return ret;
+
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_METADATA, &metadata, sizeof(metadata));
+ return ret ? ret : metadata & 1;
}
/**
- * usb4_port_retimer_is_last() - Is the retimer last on-board retimer
+ * usb4_port_retimer_is_cable() - Is the retimer cable retimer
* @port: USB4 port
* @index: Retimer index
*
- * If the retimer at @index is last one (connected directly to the
- * Type-C port) this function returns %1. If it is not returns %0. If
- * the retimer is not present returns %-ENODEV. Otherwise returns
- * negative errno.
+ * Return:
+ * * %1 - Retimer at @index is the last cable retimer.
+ * * %0 - Retimer at @index is on-board retimer.
+ * * %-ENODEV - Retimer is not present.
+ * * Negative errno - Other failure occurred.
*/
-int usb4_port_retimer_is_last(struct tb_port *port, u8 index)
+int usb4_port_retimer_is_cable(struct tb_port *port, u8 index)
{
u32 metadata;
int ret;
- ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_LAST_RETIMER,
+ ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_CABLE_RETIMER,
500);
if (ret)
return ret;
- ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata,
- sizeof(metadata));
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_METADATA, &metadata, sizeof(metadata));
return ret ? ret : metadata & 1;
}
@@ -1696,9 +1953,12 @@ int usb4_port_retimer_is_last(struct tb_port *port, u8 index)
*
* Reads NVM sector size (in bytes) of a retimer at @index. This
* operation can be used to determine whether the retimer supports NVM
- * upgrade for example. Returns sector size in bytes or negative errno
- * in case of error. Specifically returns %-ENODEV if there is no
- * retimer at @index.
+ * upgrade for example.
+ *
+ * Return:
+ * * Sector size in bytes.
+ * * %-ENODEV - If there is no retimer at @index.
+ * * Negative errno - In case of an error.
*/
int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index)
{
@@ -1710,8 +1970,8 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index)
if (ret)
return ret;
- ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata,
- sizeof(metadata));
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_METADATA, &metadata, sizeof(metadata));
return ret ? ret : metadata & USB4_NVM_SECTOR_SIZE_MASK;
}
@@ -1721,10 +1981,10 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index)
* @index: Retimer index
* @address: Start offset
*
- * Exlicitly sets NVM write offset. Normally when writing to NVM this is
+ * Explicitly sets NVM write offset. Normally when writing to NVM this is
* done automatically by usb4_port_retimer_nvm_write().
*
- * Returns %0 in success and negative errno if there was a failure.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
unsigned int address)
@@ -1736,8 +1996,8 @@ int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
metadata = (dwaddress << USB4_NVM_SET_OFFSET_SHIFT) &
USB4_NVM_SET_OFFSET_MASK;
- ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata,
- sizeof(metadata));
+ ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_METADATA, &metadata, sizeof(metadata));
if (ret)
return ret;
@@ -1759,8 +2019,8 @@ static int usb4_port_retimer_nvm_write_next_block(void *data,
u8 index = info->index;
int ret;
- ret = usb4_port_retimer_write(port, index, USB4_SB_DATA,
- buf, dwords * 4);
+ ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_DATA, buf, dwords * 4);
if (ret)
return ret;
@@ -1777,9 +2037,12 @@ static int usb4_port_retimer_nvm_write_next_block(void *data,
* @size: Size in bytes how much to write
*
* Writes @size bytes from @buf to the retimer NVM. Used for NVM
- * upgrade. Returns %0 if the data was written successfully and negative
- * errno in case of failure. Specifically returns %-ENODEV if there is
- * no retimer at @index.
+ * upgrade.
+ *
+ * Return:
+ * * %0 - If the data was written successfully.
+ * * %-ENODEV - If there is no retimer at @index.
+ * * Negative errno - In case of an error.
*/
int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, unsigned int address,
const void *buf, size_t size)
@@ -1805,6 +2068,8 @@ int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, unsigned int add
* successful the retimer restarts with the new NVM and may not have the
* index set so one needs to call usb4_port_enumerate_retimers() to
* force index to be assigned.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_port_retimer_nvm_authenticate(struct tb_port *port, u8 index)
{
@@ -1829,9 +2094,9 @@ int usb4_port_retimer_nvm_authenticate(struct tb_port *port, u8 index)
* This can be called after usb4_port_retimer_nvm_authenticate() and
* usb4_port_enumerate_retimers() to fetch status of the NVM upgrade.
*
- * Returns %0 if the authentication status was successfully read. The
+ * Return: %0 if the authentication status was successfully read. The
* completion metadata (the result) is then stored into @status. If
- * reading the status fails, returns negative errno.
+ * status read fails, returns negative errno.
*/
int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
u32 *status)
@@ -1839,8 +2104,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
u32 metadata, val;
int ret;
- ret = usb4_port_retimer_read(port, index, USB4_SB_OPCODE, &val,
- sizeof(val));
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_OPCODE, &val, sizeof(val));
if (ret)
return ret;
@@ -1851,8 +2116,9 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index,
return 0;
case -EAGAIN:
- ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA,
- &metadata, sizeof(metadata));
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_METADATA, &metadata,
+ sizeof(metadata));
if (ret)
return ret;
@@ -1877,8 +2143,8 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress,
if (dwords < USB4_DATA_DWORDS)
metadata |= dwords << USB4_NVM_READ_LENGTH_SHIFT;
- ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata,
- sizeof(metadata));
+ ret = usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_METADATA, &metadata, sizeof(metadata));
if (ret)
return ret;
@@ -1886,8 +2152,8 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress,
if (ret)
return ret;
- return usb4_port_retimer_read(port, index, USB4_SB_DATA, buf,
- dwords * 4);
+ return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_DATA, buf, dwords * 4);
}
/**
@@ -1898,9 +2164,12 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress,
* @buf: Data read from NVM is stored here
* @size: Number of bytes to read
*
- * Reads retimer NVM and copies the contents to @buf. Returns %0 if the
- * read was successful and negative errno in case of failure.
- * Specifically returns %-ENODEV if there is no retimer at @index.
+ * Reads retimer NVM and copies the contents to @buf.
+ *
+ * Return:
+ * * %0 - If the read was successful.
+ * * %-ENODEV - If there is no retimer at @index.
+ * * Negative errno - In case of an error.
*/
int usb4_port_retimer_nvm_read(struct tb_port *port, u8 index,
unsigned int address, void *buf, size_t size)
@@ -1921,11 +2190,11 @@ usb4_usb3_port_max_bandwidth(const struct tb_port *port, unsigned int bw)
}
/**
- * usb4_usb3_port_max_link_rate() - Maximum support USB3 link rate
+ * usb4_usb3_port_max_link_rate() - Maximum supported USB3 link rate
* @port: USB3 adapter port
*
- * Return maximum supported link rate of a USB3 adapter in Mb/s.
- * Negative errno in case of error.
+ * Return: Maximum supported link rate of a USB3 adapter in Mb/s.
+ * Negative errno in case of an error.
*/
int usb4_usb3_port_max_link_rate(struct tb_port *port)
{
@@ -1946,35 +2215,6 @@ int usb4_usb3_port_max_link_rate(struct tb_port *port)
return usb4_usb3_port_max_bandwidth(port, ret);
}
-/**
- * usb4_usb3_port_actual_link_rate() - Established USB3 link rate
- * @port: USB3 adapter port
- *
- * Return actual established link rate of a USB3 adapter in Mb/s. If the
- * link is not up returns %0 and negative errno in case of failure.
- */
-int usb4_usb3_port_actual_link_rate(struct tb_port *port)
-{
- int ret, lr;
- u32 val;
-
- if (!tb_port_is_usb3_down(port) && !tb_port_is_usb3_up(port))
- return -EINVAL;
-
- ret = tb_port_read(port, &val, TB_CFG_PORT,
- port->cap_adap + ADP_USB3_CS_4, 1);
- if (ret)
- return ret;
-
- if (!(val & ADP_USB3_CS_4_ULV))
- return 0;
-
- lr = val & ADP_USB3_CS_4_ALR_MASK;
- ret = lr == ADP_USB3_CS_4_ALR_20G ? 20000 : 10000;
-
- return usb4_usb3_port_max_bandwidth(port, ret);
-}
-
static int usb4_usb3_port_cm_request(struct tb_port *port, bool request)
{
int ret;
@@ -2006,7 +2246,8 @@ static int usb4_usb3_port_cm_request(struct tb_port *port, bool request)
*/
val &= ADP_USB3_CS_2_CMR;
return usb4_port_wait_for_bit(port, port->cap_adap + ADP_USB3_CS_1,
- ADP_USB3_CS_1_HCA, val, 1500);
+ ADP_USB3_CS_1_HCA, val, 1500,
+ USB4_PORT_DELAY);
}
static inline int usb4_usb3_port_set_cm_request(struct tb_port *port)
@@ -2071,8 +2312,9 @@ static int usb4_usb3_port_read_allocated_bandwidth(struct tb_port *port,
* @downstream_bw: Allocated downstream bandwidth is stored here
*
* Stores currently allocated USB3 bandwidth into @upstream_bw and
- * @downstream_bw in Mb/s. Returns %0 in case of success and negative
- * errno in failure.
+ * @downstream_bw in Mb/s.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_usb3_port_allocated_bandwidth(struct tb_port *port, int *upstream_bw,
int *downstream_bw)
@@ -2174,8 +2416,7 @@ static int usb4_usb3_port_write_allocated_bandwidth(struct tb_port *port,
* cannot be taken away by CM). The actual new values are returned in
* @upstream_bw and @downstream_bw.
*
- * Returns %0 in case of success and negative errno if there was a
- * failure.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw,
int *downstream_bw)
@@ -2217,7 +2458,7 @@ err_request:
* Releases USB3 allocated bandwidth down to what is actually consumed.
* The new bandwidth is returned in @upstream_bw and @downstream_bw.
*
- * Returns 0% in success and negative errno in case of failure.
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw,
int *downstream_bw)
@@ -2234,13 +2475,13 @@ int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw,
goto err_request;
/*
- * Always keep 1000 Mb/s to make sure xHCI has at least some
+ * Always keep 900 Mb/s to make sure xHCI has at least some
* bandwidth available for isochronous traffic.
*/
- if (consumed_up < 1000)
- consumed_up = 1000;
- if (consumed_down < 1000)
- consumed_down = 1000;
+ if (consumed_up < 900)
+ consumed_up = 900;
+ if (consumed_down < 900)
+ consumed_down = 900;
ret = usb4_usb3_port_write_allocated_bandwidth(port, consumed_up,
consumed_down);
@@ -2269,9 +2510,12 @@ static bool is_usb4_dpin(const struct tb_port *port)
* @port: DP IN adapter
* @cm_id: CM ID to assign
*
- * Sets CM ID for the @port. Returns %0 on success and negative errno
- * otherwise. Speficially returns %-EOPNOTSUPP if the @port does not
- * support this.
+ * Sets CM ID for the @port.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the @port does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_set_cm_id(struct tb_port *port, int cm_id)
{
@@ -2298,8 +2542,10 @@ int usb4_dp_port_set_cm_id(struct tb_port *port, int cm_id)
* supported
* @port: DP IN adapter to check
*
- * Can be called to any DP IN adapter. Returns true if the adapter
- * supports USB4 bandwidth allocation mode, false otherwise.
+ * Can be called to any DP IN adapter.
+ *
+ * Return: %true if the adapter supports USB4 bandwidth allocation mode,
+ * %false otherwise.
*/
bool usb4_dp_port_bandwidth_mode_supported(struct tb_port *port)
{
@@ -2322,8 +2568,10 @@ bool usb4_dp_port_bandwidth_mode_supported(struct tb_port *port)
* enabled
* @port: DP IN adapter to check
*
- * Can be called to any DP IN adapter. Returns true if the bandwidth
- * allocation mode has been enabled, false otherwise.
+ * Can be called to any DP IN adapter.
+ *
+ * Return: %true if the bandwidth allocation mode has been enabled,
+ * %false otherwise.
*/
bool usb4_dp_port_bandwidth_mode_enabled(struct tb_port *port)
{
@@ -2348,9 +2596,12 @@ bool usb4_dp_port_bandwidth_mode_enabled(struct tb_port *port)
* @supported: Does the CM support bandwidth allocation mode
*
* Can be called to any DP IN adapter. Sets or clears the CM support bit
- * of the DP IN adapter. Returns %0 in success and negative errno
- * otherwise. Specifically returns %-OPNOTSUPP if the passed in adapter
- * does not support this.
+ * of the DP IN adapter.
+ *
+ * * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the passed IN adapter does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_set_cm_bandwidth_mode_supported(struct tb_port *port,
bool supported)
@@ -2380,8 +2631,12 @@ int usb4_dp_port_set_cm_bandwidth_mode_supported(struct tb_port *port,
* @port: DP IN adapter
*
* Reads bandwidth allocation Group ID from the DP IN adapter and
- * returns it. If the adapter does not support setting Group_ID
- * %-EOPNOTSUPP is returned.
+ * returns it.
+ *
+ * Return:
+ * * Group ID assigned to adapter @port.
+ * * %-EOPNOTSUPP - If adapter does not support setting GROUP_ID.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_group_id(struct tb_port *port)
{
@@ -2405,9 +2660,11 @@ int usb4_dp_port_group_id(struct tb_port *port)
* @group_id: Group ID for the adapter
*
* Sets bandwidth allocation mode Group ID for the DP IN adapter.
- * Returns %0 in case of success and negative errno otherwise.
- * Specifically returns %-EOPNOTSUPP if the adapter does not support
- * this.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the adapter does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_set_group_id(struct tb_port *port, int group_id)
{
@@ -2435,9 +2692,12 @@ int usb4_dp_port_set_group_id(struct tb_port *port, int group_id)
* @rate: Non-reduced rate in Mb/s is placed here
* @lanes: Non-reduced lanes are placed here
*
- * Reads the non-reduced rate and lanes from the DP IN adapter. Returns
- * %0 in success and negative errno otherwise. Specifically returns
- * %-EOPNOTSUPP if the adapter does not support this.
+ * Reads the non-reduced rate and lanes from the DP IN adapter.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the adapter does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_nrd(struct tb_port *port, int *rate, int *lanes)
{
@@ -2490,10 +2750,13 @@ int usb4_dp_port_nrd(struct tb_port *port, int *rate, int *lanes)
* @rate: Non-reduced rate in Mb/s
* @lanes: Non-reduced lanes
*
- * Before the capabilities reduction this function can be used to set
- * the non-reduced values for the DP IN adapter. Returns %0 in success
- * and negative errno otherwise. If the adapter does not support this
- * %-EOPNOTSUPP is returned.
+ * Before the capabilities reduction, this function can be used to set
+ * the non-reduced values for the DP IN adapter.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the adapter does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_set_nrd(struct tb_port *port, int rate, int lanes)
{
@@ -2552,9 +2815,13 @@ int usb4_dp_port_set_nrd(struct tb_port *port, int rate, int lanes)
* usb4_dp_port_granularity() - Return granularity for the bandwidth values
* @port: DP IN adapter
*
- * Reads the programmed granularity from @port. If the DP IN adapter does
- * not support bandwidth allocation mode returns %-EOPNOTSUPP and negative
- * errno in other error cases.
+ * Reads the programmed granularity from @port.
+ *
+ * Return:
+ * * Granularity value of a @port.
+ * * %-EOPNOTSUPP - If the DP IN adapter does not support bandwidth
+ * allocation mode.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_granularity(struct tb_port *port)
{
@@ -2590,8 +2857,12 @@ int usb4_dp_port_granularity(struct tb_port *port)
* @granularity: Granularity in Mb/s. Supported values: 1000, 500 and 250.
*
* Sets the granularity used with the estimated, allocated and requested
- * bandwidth. Returns %0 in success and negative errno otherwise. If the
- * adapter does not support this %-EOPNOTSUPP is returned.
+ * bandwidth.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the adapter does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_set_granularity(struct tb_port *port, int granularity)
{
@@ -2632,10 +2903,13 @@ int usb4_dp_port_set_granularity(struct tb_port *port, int granularity)
* @bw: Estimated bandwidth in Mb/s.
*
* Sets the estimated bandwidth to @bw. Set the granularity by calling
- * usb4_dp_port_set_granularity() before calling this. The @bw is round
- * down to the closest granularity multiplier. Returns %0 in success
- * and negative errno otherwise. Specifically returns %-EOPNOTSUPP if
- * the adapter does not support this.
+ * usb4_dp_port_set_granularity() before calling this. The @bw is rounded
+ * down to the closest granularity multiplier.
+ *
+ * Return:
+ * * %0 - On success.
+ * * %-EOPNOTSUPP - If the adapter does not support this.
+ * * Negative errno - Another error occurred.
*/
int usb4_dp_port_set_estimated_bandwidth(struct tb_port *port, int bw)
{
@@ -2666,9 +2940,10 @@ int usb4_dp_port_set_estimated_bandwidth(struct tb_port *port, int bw)
* usb4_dp_port_allocated_bandwidth() - Return allocated bandwidth
* @port: DP IN adapter
*
- * Reads and returns allocated bandwidth for @port in Mb/s (taking into
- * account the programmed granularity). Returns negative errno in case
- * of error.
+ * Reads the allocated bandwidth for @port in Mb/s (taking into account
+ * the programmed granularity).
+ *
+ * Return: Allocated bandwidth in Mb/s or negative errno in case of an error.
*/
int usb4_dp_port_allocated_bandwidth(struct tb_port *port)
{
@@ -2742,8 +3017,10 @@ static int usb4_dp_port_wait_and_clear_cm_ack(struct tb_port *port,
usleep_range(50, 100);
} while (ktime_before(ktime_get(), end));
- if (val & ADP_DP_CS_8_DR)
+ if (val & ADP_DP_CS_8_DR) {
+ tb_port_warn(port, "timeout waiting for DPTX request to clear\n");
return -ETIMEDOUT;
+ }
ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_adap + ADP_DP_CS_2, 1);
@@ -2761,8 +3038,9 @@ static int usb4_dp_port_wait_and_clear_cm_ack(struct tb_port *port,
* @bw: New allocated bandwidth in Mb/s
*
* Communicates the new allocated bandwidth with the DPCD (graphics
- * driver). Takes into account the programmed granularity. Returns %0 in
- * success and negative errno in case of error.
+ * driver). Takes into account the programmed granularity.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_dp_port_allocate_bandwidth(struct tb_port *port, int bw)
{
@@ -2802,10 +3080,15 @@ int usb4_dp_port_allocate_bandwidth(struct tb_port *port, int bw)
* @port: DP IN adapter
*
* Reads the DPCD (graphics driver) requested bandwidth and returns it
- * in Mb/s. Takes the programmed granularity into account. In case of
- * error returns negative errno. Specifically returns %-EOPNOTSUPP if
- * the adapter does not support bandwidth allocation mode, and %ENODATA
- * if there is no active bandwidth request from the graphics driver.
+ * in Mb/s. Takes the programmed granularity into account.
+ *
+ * Return:
+ * * Requested bandwidth in Mb/s - On success.
+ * * %-EOPNOTSUPP - If the adapter does not support bandwidth allocation
+ * mode.
+ * * %ENODATA - If there is no active bandwidth request from the graphics
+ * driver.
+ * * Negative errno - On failure.
*/
int usb4_dp_port_requested_bandwidth(struct tb_port *port)
{
@@ -2837,8 +3120,9 @@ int usb4_dp_port_requested_bandwidth(struct tb_port *port)
* @enable: Enable/disable extended encapsulation
*
* Enables or disables extended encapsulation used in PCIe tunneling. Caller
- * needs to make sure both adapters support this before enabling. Returns %0 on
- * success and negative errno otherwise.
+ * needs to make sure both adapters support this before enabling.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int usb4_pci_port_set_ext_encapsulation(struct tb_port *port, bool enable)
{