summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/retimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thunderbolt/retimer.c')
-rw-r--r--drivers/thunderbolt/retimer.c95
1 files changed, 63 insertions, 32 deletions
diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c
index 6bb49bdcd6c1..361fece3d818 100644
--- a/drivers/thunderbolt/retimer.c
+++ b/drivers/thunderbolt/retimer.c
@@ -14,7 +14,11 @@
#include "sb_regs.h"
#include "tb.h"
+#if IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING)
#define TB_MAX_RETIMER_INDEX 6
+#else
+#define TB_MAX_RETIMER_INDEX 2
+#endif
/**
* tb_retimer_nvm_read() - Read contents of retimer NVM
@@ -89,9 +93,11 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt)
if (ret)
goto err_nvm;
- ret = tb_nvm_add_non_active(nvm, nvm_write);
- if (ret)
- goto err_nvm;
+ if (!rt->no_nvm_upgrade) {
+ ret = tb_nvm_add_non_active(nvm, nvm_write);
+ if (ret)
+ goto err_nvm;
+ }
rt->nvm = nvm;
dev_dbg(&rt->dev, "NVM version %x.%x\n", nvm->major, nvm->minor);
@@ -99,6 +105,7 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt)
err_nvm:
dev_dbg(&rt->dev, "NVM upgrade disabled\n");
+ rt->no_nvm_upgrade = true;
if (!IS_ERR(nvm))
tb_nvm_free(nvm);
@@ -178,8 +185,6 @@ static ssize_t nvm_authenticate_show(struct device *dev,
if (!rt->nvm)
ret = -EAGAIN;
- else if (rt->no_nvm_upgrade)
- ret = -EOPNOTSUPP;
else
ret = sysfs_emit(buf, "%#x\n", rt->auth_status);
@@ -199,8 +204,10 @@ static void tb_retimer_nvm_authenticate_status(struct tb_port *port, u32 *status
* If the retimer has it set, store it for the new retimer
* device instance.
*/
- for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
- usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]);
+ for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
+ if (usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]))
+ break;
+ }
}
static void tb_retimer_set_inbound_sbtx(struct tb_port *port)
@@ -234,8 +241,10 @@ static void tb_retimer_unset_inbound_sbtx(struct tb_port *port)
tb_port_dbg(port, "disabling sideband transactions\n");
- for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--)
- usb4_port_retimer_unset_inbound_sbtx(port, i);
+ for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--) {
+ if (usb4_port_retimer_unset_inbound_sbtx(port, i))
+ break;
+ }
}
static ssize_t nvm_authenticate_store(struct device *dev,
@@ -332,6 +341,19 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(vendor);
+static umode_t retimer_is_visible(struct kobject *kobj, struct attribute *attr,
+ int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct tb_retimer *rt = tb_to_retimer(dev);
+
+ if (attr == &dev_attr_nvm_authenticate.attr ||
+ attr == &dev_attr_nvm_version.attr)
+ return rt->no_nvm_upgrade ? 0 : attr->mode;
+
+ return attr->mode;
+}
+
static struct attribute *retimer_attrs[] = {
&dev_attr_device.attr,
&dev_attr_nvm_authenticate.attr,
@@ -341,6 +363,7 @@ static struct attribute *retimer_attrs[] = {
};
static const struct attribute_group retimer_group = {
+ .is_visible = retimer_is_visible,
.attrs = retimer_attrs,
};
@@ -362,35 +385,29 @@ const struct device_type tb_retimer_type = {
.release = tb_retimer_release,
};
-static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
+static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status,
+ bool on_board)
{
struct tb_retimer *rt;
u32 vendor, device;
int ret;
- ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor,
- sizeof(vendor));
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_VENDOR_ID, &vendor, sizeof(vendor));
if (ret) {
if (ret != -ENODEV)
tb_port_warn(port, "failed read retimer VendorId: %d\n", ret);
return ret;
}
- ret = usb4_port_retimer_read(port, index, USB4_SB_PRODUCT_ID, &device,
- sizeof(device));
+ ret = usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index,
+ USB4_SB_PRODUCT_ID, &device, sizeof(device));
if (ret) {
if (ret != -ENODEV)
tb_port_warn(port, "failed read retimer ProductId: %d\n", ret);
return ret;
}
- /*
- * Check that it supports NVM operations. If not then don't add
- * the device at all.
- */
- ret = usb4_port_retimer_nvm_sector_size(port, index);
- if (ret < 0)
- return ret;
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
if (!rt)
@@ -403,6 +420,13 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
rt->port = port;
rt->tb = port->sw->tb;
+ /*
+ * Only support NVM upgrade for on-board retimers. The retimers
+ * on the other side of the connection.
+ */
+ if (!on_board || usb4_port_retimer_nvm_sector_size(port, index) <= 0)
+ rt->no_nvm_upgrade = true;
+
rt->dev.parent = &port->usb4->dev;
rt->dev.bus = &tb_bus_type;
rt->dev.type = &tb_retimer_type;
@@ -433,12 +457,14 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
pm_runtime_mark_last_busy(&rt->dev);
pm_runtime_use_autosuspend(&rt->dev);
+ tb_retimer_debugfs_init(rt);
return 0;
}
static void tb_retimer_remove(struct tb_retimer *rt)
{
dev_info(&rt->dev, "retimer disconnected\n");
+ tb_retimer_debugfs_remove(rt);
tb_nvm_free(rt->nvm);
device_unregister(&rt->dev);
}
@@ -448,7 +474,7 @@ struct tb_retimer_lookup {
u8 index;
};
-static int retimer_match(struct device *dev, void *data)
+static int retimer_match(struct device *dev, const void *data)
{
const struct tb_retimer_lookup *lookup = data;
struct tb_retimer *rt = tb_to_retimer(dev);
@@ -481,7 +507,7 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
int tb_retimer_scan(struct tb_port *port, bool add)
{
u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
- int ret, i, last_idx = 0;
+ int ret, i, max, last_idx = 0;
/*
* Send broadcast RT to make sure retimer indices facing this
@@ -503,7 +529,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
*/
tb_retimer_set_inbound_sbtx(port);
- for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
+ for (max = 1, i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
/*
* Last retimer is true only for the last on-board
* retimer (the one connected directly to the Type-C
@@ -514,28 +540,33 @@ int tb_retimer_scan(struct tb_port *port, bool add)
last_idx = i;
else if (ret < 0)
break;
- }
-
- tb_retimer_unset_inbound_sbtx(port);
- if (!last_idx)
- return 0;
+ max = i;
+ }
- /* Add on-board retimers if they do not exist already */
ret = 0;
- for (i = 1; i <= last_idx; i++) {
+ if (!IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING))
+ max = min(last_idx, max);
+
+ /* Add retimers if they do not exist already */
+ for (i = 1; i <= max; i++) {
struct tb_retimer *rt;
+ /* Skip cable retimers */
+ if (usb4_port_retimer_is_cable(port, i))
+ continue;
+
rt = tb_port_find_retimer(port, i);
if (rt) {
put_device(&rt->dev);
} else if (add) {
- ret = tb_retimer_add(port, i, status[i]);
+ ret = tb_retimer_add(port, i, status[i], i <= last_idx);
if (ret && ret != -EOPNOTSUPP)
break;
}
}
+ tb_retimer_unset_inbound_sbtx(port);
return ret;
}