thunderbolt: Add WRITE_ONLY and AUTHENTICATE_ONLY NVM operations for retimers

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>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Rajmohan Mani 2021-04-12 15:29:16 +03:00 коммит произвёл Mika Westerberg
Родитель 1cbf680f76
Коммит faa1c615f0
4 изменённых файлов: 53 добавлений и 17 удалений

Просмотреть файл

@ -221,7 +221,7 @@ Description: When new NVM image is written to the non-active NVM
and flush it to the storage area. and flush it to the storage area.
- Writing "3" will authenticate the image that is - Writing "3" will authenticate the image that is
currently written in the storage area. This is only 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 When read holds status of the last authentication
operation if an error occurred during the process. This operation if an error occurred during the process. This

Просмотреть файл

@ -103,6 +103,7 @@ static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
unsigned int image_size, hdr_size; unsigned int image_size, hdr_size;
const u8 *buf = rt->nvm->buf; const u8 *buf = rt->nvm->buf;
u16 ds_size, device; u16 ds_size, device;
int ret;
image_size = rt->nvm->buf_data_size; image_size = rt->nvm->buf_data_size;
if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_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; buf += hdr_size;
image_size -= hdr_size; image_size -= hdr_size;
return usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf, ret = usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
image_size); 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, 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 device_attribute *attr, const char *buf, size_t count)
{ {
struct tb_retimer *rt = tb_to_retimer(dev); struct tb_retimer *rt = tb_to_retimer(dev);
bool val; int val, ret;
int ret;
pm_runtime_get_sync(&rt->dev); pm_runtime_get_sync(&rt->dev);
@ -191,7 +208,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
goto exit_unlock; goto exit_unlock;
} }
ret = kstrtobool(buf, &val); ret = kstrtoint(buf, 10, &val);
if (ret) if (ret)
goto exit_unlock; goto exit_unlock;
@ -199,16 +216,22 @@ static ssize_t nvm_authenticate_store(struct device *dev,
rt->auth_status = 0; rt->auth_status = 0;
if (val) { if (val) {
if (!rt->nvm->buf) { if (val == AUTHENTICATE_ONLY) {
ret = -EINVAL; ret = tb_retimer_nvm_authenticate(rt, true);
goto exit_unlock; } 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: exit_unlock:

Просмотреть файл

@ -1082,6 +1082,8 @@ int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,
const void *buf, u8 size); const void *buf, u8 size);
int usb4_port_retimer_is_last(struct tb_port *port, u8 index); 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_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, int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index,
unsigned int address, const void *buf, unsigned int address, const void *buf,
size_t size); size_t size);

Просмотреть файл

@ -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; 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; u32 metadata, dwaddress;
int ret; int ret;