summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/switch.c
diff options
context:
space:
mode:
authorMario Limonciello <mario.limonciello@dell.com>2020-06-23 11:14:29 -0500
committerMika Westerberg <mika.westerberg@linux.intel.com>2020-07-01 13:51:49 +0300
commit1cb36293833766e048cba2026dd860687a2851d9 (patch)
tree1922fd625b49827fb65cccd15469e1359b867491 /drivers/thunderbolt/switch.c
parent4b794f8066e84818c172c81024f1d61071f14710 (diff)
thunderbolt: Add support for authenticate on disconnect
Some external devices can support completing thunderbolt authentication when they are unplugged. For this to work though, the link controller must remain operational. The only device known to support this right now is the Dell WD19TB, so add a quirk for this. Signed-off-by: Mario Limonciello <mario.limonciello@dell.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/thunderbolt/switch.c')
-rw-r--r--drivers/thunderbolt/switch.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index bbfbfebeee7f..712395f518b8 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1493,8 +1493,8 @@ static ssize_t nvm_authenticate_show(struct device *dev,
return sprintf(buf, "%#x\n", status);
}
-static ssize_t nvm_authenticate_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
+ bool disconnect)
{
struct tb_switch *sw = tb_to_switch(dev);
int val;
@@ -1532,8 +1532,12 @@ static ssize_t nvm_authenticate_store(struct device *dev,
goto exit_unlock;
}
if (val == WRITE_AND_AUTHENTICATE) {
- sw->nvm->authenticating = true;
- ret = nvm_authenticate(sw);
+ if (disconnect) {
+ ret = tb_lc_force_power(sw);
+ } else {
+ sw->nvm->authenticating = true;
+ ret = nvm_authenticate(sw);
+ }
}
}
@@ -1543,12 +1547,35 @@ exit_rpm:
pm_runtime_mark_last_busy(&sw->dev);
pm_runtime_put_autosuspend(&sw->dev);
+ return ret;
+}
+
+static ssize_t nvm_authenticate_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret = nvm_authenticate_sysfs(dev, buf, false);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(nvm_authenticate);
+static ssize_t nvm_authenticate_on_disconnect_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return nvm_authenticate_show(dev, attr, buf);
+}
+
+static ssize_t nvm_authenticate_on_disconnect_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+
+ ret = nvm_authenticate_sysfs(dev, buf, true);
+ return ret ? ret : count;
+}
+static DEVICE_ATTR_RW(nvm_authenticate_on_disconnect);
+
static ssize_t nvm_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1606,6 +1633,7 @@ static struct attribute *switch_attrs[] = {
&dev_attr_generation.attr,
&dev_attr_key.attr,
&dev_attr_nvm_authenticate.attr,
+ &dev_attr_nvm_authenticate_on_disconnect.attr,
&dev_attr_nvm_version.attr,
&dev_attr_rx_speed.attr,
&dev_attr_rx_lanes.attr,
@@ -1660,6 +1688,10 @@ static umode_t switch_attr_is_visible(struct kobject *kobj,
if (tb_route(sw))
return attr->mode;
return 0;
+ } else if (attr == &dev_attr_nvm_authenticate_on_disconnect.attr) {
+ if (sw->quirks & QUIRK_FORCE_POWER_LINK_CONTROLLER)
+ return attr->mode;
+ return 0;
}
return sw->safe_mode ? 0 : attr->mode;