]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
thunderbolt: Allow router NVM authenticate separately
authorMika Westerberg <mika.westerberg@linux.intel.com>
Mon, 12 Apr 2021 12:25:08 +0000 (15:25 +0300)
committerMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 1 Jun 2021 07:53:32 +0000 (10:53 +0300)
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: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-bus-thunderbolt
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/usb4.c

index f6743dc33aacd5bacf5d7618c119c36baaaea0cd..da580b504c8703d6eb4072b600aaf848ca1c171a 100644 (file)
@@ -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
index bf4821d3bbabe8605f1b71e58de0bdd95dc28fc0..83b1ef3d5d037527b243b5fced51946a91d27c57 100644 (file)
@@ -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,22 +1746,27 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
        nvm_clear_auth_status(sw);
 
        if (val > 0) {
-               if (!sw->nvm->flushed) {
-                       if (!sw->nvm->buf) {
+               if (val == AUTHENTICATE_ONLY) {
+                       if (disconnect)
                                ret = -EINVAL;
-                               goto exit_unlock;
+                       else
+                               ret = nvm_authenticate(sw, true);
+               } else {
+                       if (!sw->nvm->flushed) {
+                               if (!sw->nvm->buf) {
+                                       ret = -EINVAL;
+                                       goto exit_unlock;
+                               }
+
+                               ret = nvm_validate_and_write(sw);
+                               if (ret || val == WRITE_ONLY)
+                                       goto exit_unlock;
                        }
-
-                       ret = nvm_validate_and_write(sw);
-                       if (ret || val == WRITE_ONLY)
-                               goto exit_unlock;
-               }
-               if (val == WRITE_AND_AUTHENTICATE) {
-                       if (disconnect) {
-                               ret = tb_lc_force_power(sw);
-                       } else {
-                               sw->nvm->authenticating = true;
-                               ret = nvm_authenticate(sw);
+                       if (val == WRITE_AND_AUTHENTICATE) {
+                               if (disconnect)
+                                       ret = tb_lc_force_power(sw);
+                               else
+                                       ret = nvm_authenticate(sw, false);
                        }
                }
        }
index 863d80ad44abd76170854585514d663d1f39ecef..53f6bb85b178905ecd6bb822a474283e0ba6cdb9 100644 (file)
@@ -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);
index 8af96dbaa7a7fc06542dcc469c5d25f444e5624e..76d7335aa4401ced98ebe4e25f0d177ec82d4fcb 100644 (file)
@@ -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;