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:
Родитель
1cbf680f76
Коммит
faa1c615f0
|
@ -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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче