Commit 1cbf680f authored by Mika Westerberg's avatar Mika Westerberg
Browse files

thunderbolt: Allow router NVM authenticate separately



It may be useful if the actual NVM authentication can be delayed to be
run later, for instance when the user logs out. For this reason add a
new NVM operation (AUHENTICATE_ONLY) that just triggers the authentication
procedure over whatever was written to the NVM storage.

This is not supported with Thunderbolt 1-3 devices, though.

Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ff3a8306
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -213,12 +213,15 @@ Description: When new NVM image is written to the non-active NVM
		restarted with the new NVM firmware. If the image
		verification fails an error code is returned instead.

		This file will accept writing values "1" or "2"
		This file will accept writing values "1", "2" or "3".

		- Writing "1" will flush the image to the storage
		  area and authenticate the image in one action.
		- Writing "2" will run some basic validation on the image
		  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.

		When read holds status of the last authentication
		operation if an error occurred during the process. This
+32 −18
Original line number Diff line number Diff line
@@ -303,13 +303,23 @@ static inline int nvm_read(struct tb_switch *sw, unsigned int address,
	return dma_port_flash_read(sw->dma_port, address, buf, size);
}

static int nvm_authenticate(struct tb_switch *sw)
static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
{
	int ret;

	if (tb_switch_is_usb4(sw))
	if (tb_switch_is_usb4(sw)) {
		if (auth_only) {
			ret = usb4_switch_nvm_set_offset(sw, 0);
			if (ret)
				return ret;
		}
		sw->nvm->authenticating = true;
		return usb4_switch_nvm_authenticate(sw);
	} else if (auth_only) {
		return -EOPNOTSUPP;
	}

	sw->nvm->authenticating = true;
	if (!tb_route(sw)) {
		nvm_authenticate_start_dma_port(sw);
		ret = nvm_authenticate_host_dma_port(sw);
@@ -1713,8 +1723,7 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
				      bool disconnect)
{
	struct tb_switch *sw = tb_to_switch(dev);
	int val;
	int ret;
	int val, ret;

	pm_runtime_get_sync(&sw->dev);

@@ -1737,6 +1746,12 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
	nvm_clear_auth_status(sw);

	if (val > 0) {
		if (val == AUTHENTICATE_ONLY) {
			if (disconnect)
				ret = -EINVAL;
			else
				ret = nvm_authenticate(sw, true);
		} else {
			if (!sw->nvm->flushed) {
				if (!sw->nvm->buf) {
					ret = -EINVAL;
@@ -1748,11 +1763,10 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
					goto exit_unlock;
			}
			if (val == WRITE_AND_AUTHENTICATE) {
			if (disconnect) {
				if (disconnect)
					ret = tb_lc_force_power(sw);
			} else {
				sw->nvm->authenticating = true;
				ret = nvm_authenticate(sw);
				else
					ret = nvm_authenticate(sw, false);
			}
		}
	}
+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ struct tb_nvm {
enum tb_nvm_write_ops {
	WRITE_AND_AUTHENTICATE = 1,
	WRITE_ONLY = 2,
	AUTHENTICATE_ONLY = 3,
};

#define TB_SWITCH_KEY_SIZE		32
@@ -1049,6 +1050,7 @@ int usb4_switch_set_sleep(struct tb_switch *sw);
int usb4_switch_nvm_sector_size(struct tb_switch *sw);
int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
			 size_t size);
int usb4_switch_nvm_set_offset(struct tb_switch *sw, unsigned int address);
int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address,
			  const void *buf, size_t size);
int usb4_switch_nvm_authenticate(struct tb_switch *sw);
+11 −2
Original line number Diff line number Diff line
@@ -547,8 +547,17 @@ int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
				usb4_switch_nvm_read_block, sw);
}

static int usb4_switch_nvm_set_offset(struct tb_switch *sw,
				      unsigned int address)
/**
 * usb4_switch_nvm_set_offset() - Set NVM write offset
 * @sw: USB4 router
 * @address: Start offset
 *
 * Explicitly sets NVM write offset. Normally when writing to NVM this
 * is done automatically by usb4_switch_nvm_write().
 *
 * Returns %0 in success and negative errno if there was a failure.
 */
int usb4_switch_nvm_set_offset(struct tb_switch *sw, unsigned int address)
{
	u32 metadata, dwaddress;
	u8 status = 0;