[PATCH 8/9] thunderbolt: Add WRITE_ONLY and AUTHENTICATE_ONLY NVM operations for retimers

Mika Westerberg
2021-05-19T14:12:51Z

From: Rajmohan Mani <rajmohan.mani@intel.com>

The same way we support these two operations for USB4 routers we can
extend the retimer NVM operations to support retimers also.

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>
---
.../ABI/testing/sysfs-bus-thunderbolt | 2 +-
drivers/thunderbolt/retimer.c | 51 ++++++++++++++-----
drivers/thunderbolt/tb.h | 2 +
drivers/thunderbolt/usb4.c | 15 +++++-
4 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt
index da580b504c87..95c21d6c9a84 100644
--- a/Documentation/ABI/testing/sysfs-bus-thunderbolt
+++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt
@@ -221,7 +221,7 @@ Description: When new NVM image is written to the non-active NVM
and flush it to the storage area.
- Writing "3" will authenticate the image that is
currently written in the storage area. This is only
- supported with USB4 devices.
+ supported with USB4 devices and retimers.

When read holds status of the last authentication
operation if an error occurred during the process. This
diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c
index 05af0feefe84..3aa790aa6500 100644
--- a/drivers/thunderbolt/retimer.c
+++ b/drivers/thunderbolt/retimer.c
@@ -103,6 +103,7 @@ static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
unsigned int image_size, hdr_size;
const u8 *buf = rt->nvm->buf;
u16 ds_size, device;
+ int ret;

image_size = rt->nvm->buf_data_size;
if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE)
@@ -140,8 +141,25 @@ static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
buf += hdr_size;
image_size -= hdr_size;

- return usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
- image_size);
+ ret = usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
+ image_size);
+ if (!ret)
+ rt->nvm->flushed = true;
+
+ return ret;
+}
+
+static int tb_retimer_nvm_authenticate(struct tb_retimer *rt, bool auth_only)
+{
+ int ret;
+
+ if (auth_only) {
+ ret = usb4_port_retimer_nvm_set_offset(rt->port, rt->index, 0);
+ if (ret)
+ return ret;
+ }
+
+ return usb4_port_retimer_nvm_authenticate(rt->port, rt->index);
}

static ssize_t device_show(struct device *dev, struct device_attribute *attr,
@@ -176,8 +194,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tb_retimer *rt = tb_to_retimer(dev);
- bool val;
- int ret;
+ int val, ret;

pm_runtime_get_sync(&rt->dev);

@@ -191,7 +208,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
goto exit_unlock;
}

- ret = kstrtobool(buf, &val);
+ ret = kstrtoint(buf, 10, &val);
if (ret)
goto exit_unlock;

@@ -199,16 +216,22 @@ static ssize_t nvm_authenticate_store(struct device *dev,
rt->auth_status = 0;

if (val) {
- if (!rt->nvm->buf) {
- ret = -EINVAL;
- goto exit_unlock;
+ if (val == AUTHENTICATE_ONLY) {
+ ret = tb_retimer_nvm_authenticate(rt, true);
+ } else {
+ if (!rt->nvm->flushed) {
+ if (!rt->nvm->buf) {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ ret = tb_retimer_nvm_validate_and_write(rt);
+ if (ret || val == WRITE_ONLY)
+ goto exit_unlock;
+ }
+ if (val == WRITE_AND_AUTHENTICATE)
+ ret = tb_retimer_nvm_authenticate(rt, false);
}
-
- ret = tb_retimer_nvm_validate_and_write(rt);
- if (ret)
- goto exit_unlock;
-
- ret = usb4_port_retimer_nvm_authenticate(rt->port, rt->index);
}

exit_unlock:
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 53f6bb85b178..725104c83e3d 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1082,6 +1082,8 @@ int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,
const void *buf, u8 size);
int usb4_port_retimer_is_last(struct tb_port *port, u8 index);
int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index);
+int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
+ unsigned int address);
int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index,
unsigned int address, const void *buf,
size_t size);
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 76d7335aa440..ceddbe7e9f93 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -1513,8 +1513,19 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index)
return ret ? ret : metadata & USB4_NVM_SECTOR_SIZE_MASK;
}

-static int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
- unsigned int address)
+/**
+ * usb4_port_retimer_nvm_set_offset() - Set NVM write offset
+ * @port: USB4 port
+ * @index: Retimer index
+ * @address: Start offset
+ *
+ * Exlicitly 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.
+ */
+int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
+ unsigned int address)
{
u32 metadata, dwaddress;
int ret;
--
2.30.2