From patchwork Thu Dec 3 08:18:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: You-Sheng Yang X-Patchwork-Id: 1410189 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Cmpf04CmCz9sT5; Thu, 3 Dec 2020 19:19:20 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1kkjpd-0004tk-6u; Thu, 03 Dec 2020 08:19:17 +0000 Received: from mail-pj1-f67.google.com ([209.85.216.67]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1kkjpa-0004pj-26 for kernel-team@lists.ubuntu.com; Thu, 03 Dec 2020 08:19:14 +0000 Received: by mail-pj1-f67.google.com with SMTP id p21so1724771pjv.0 for ; Thu, 03 Dec 2020 00:19:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=JZoB8asw3bYmWJNEk5eCeRpOpnHF5DuZq2pfCIxw9HM=; b=GMFvyg5AVoWX/ZPbIAvNIR3IApqJm53F+62RwITTQvV3Zy6ES7NnAGhSD6IycfRBUW z+/I9h7RU3OED4VVskiA7lcbSU1NJG954a3XhPH3w8UwPDzrzOCYdV85jqmBovRsnl1E r0zRODSTeDlmgdKBWC5V8aIkkXMYXGUq1xCItnth9/F3E5EkEZIqT47aV9URoBOIMczy YNkqFVII+XeOHhiDfzj35cqHVdsSSrNG4CeIPrTKgwEGDPqRqyWQZGYI8J/RQnrsllay QWSL+uEIfD2yh+kZnnXXTH2/gct1eV7+ATBIgu2MWfsJdRE0P5ichwWEzfTvaSHcgXhB lxLA== X-Gm-Message-State: AOAM532U5HTOwphN+6rVujBhAwTLhzgbv8my9uRYPG0HQWtsweuBBAZr tP4A85VlZIHqM3NhFYbEY5VQv/JSePXGuQ== X-Google-Smtp-Source: ABdhPJwxHGekRgaF7pgsDIT5R/V77lnOQOinolyOdH9XpaL7GJwekKzlM9qO3M/V0ui7CbYCN5RKVw== X-Received: by 2002:a17:90a:de94:: with SMTP id n20mr2095904pjv.196.1606983551037; Thu, 03 Dec 2020 00:19:11 -0800 (PST) Received: from localhost (61-220-137-37.HINET-IP.hinet.net. [61.220.137.37]) by smtp.gmail.com with ESMTPSA id p127sm866181pfp.93.2020.12.03.00.19.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Dec 2020 00:19:10 -0800 (PST) From: You-Sheng Yang To: kernel-team@lists.ubuntu.com Subject: [PATCH 06/13][SRU][U/OEM-5.10] UBUNTU: SAUCE: thunderbolt: Perform USB4 router NVM upgrade in two phases Date: Thu, 3 Dec 2020 16:18:45 +0800 Message-Id: <20201203081852.754141-7-vicamo.yang@canonical.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201203081852.754141-1-vicamo.yang@canonical.com> References: <20201203081852.754141-1-vicamo.yang@canonical.com> MIME-Version: 1.0 Received-SPF: pass client-ip=209.85.216.67; envelope-from=vicamo@gmail.com; helo=mail-pj1-f67.google.com X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Mika Westerberg BugLink: https://bugs.launchpad.net/bugs/1906236 The currect code expects that the router returns back the status of the NVM authentication immediately. When tested against a real USB4 device what happens is that the router is reset and only after that the result is updated in the ROUTER_CS_26 register status field. This also seems to align better what the spec suggests. For this reason do the same what we already do with the Thunderbolt 3 devices and perform the NVM upgrade in two phases. First start the NVM_AUTH router operation and once the router is added back after the reset read the status in ROUTER_CS_26 and expose it to the userspace accordingly. Signed-off-by: Mika Westerberg (cherry picked from commit 661b19473bf3ac0924560f0cbf84c15458b3c8de git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git) Signed-off-by: You-Sheng Yang --- drivers/thunderbolt/switch.c | 20 ++++++++-- drivers/thunderbolt/tb.h | 1 + drivers/thunderbolt/tb_regs.h | 1 + drivers/thunderbolt/usb4.c | 75 +++++++++++++++++++++++++++-------- 4 files changed, 77 insertions(+), 20 deletions(-) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index c73bbfe69ba1..c99a2111ffb6 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -2135,6 +2135,7 @@ static int tb_switch_add_dma_port(struct tb_switch *sw) fallthrough; case 3: + case 4: ret = tb_switch_set_uuid(sw); if (ret) return ret; @@ -2150,6 +2151,22 @@ static int tb_switch_add_dma_port(struct tb_switch *sw) break; } + if (sw->no_nvm_upgrade) + return 0; + + if (tb_switch_is_usb4(sw)) { + ret = usb4_switch_nvm_authenticate_status(sw, &status); + if (ret) + return ret; + + if (status) { + tb_sw_info(sw, "switch flash authentication failed\n"); + nvm_set_auth_status(sw, status); + } + + return 0; + } + /* Root switch DMA port requires running firmware */ if (!tb_route(sw) && !tb_switch_is_icm(sw)) return 0; @@ -2158,9 +2175,6 @@ static int tb_switch_add_dma_port(struct tb_switch *sw) if (!sw->dma_port) return 0; - if (sw->no_nvm_upgrade) - return 0; - /* * If there is status already set then authentication failed * when the dma_port_flash_update_auth() returned. Power cycling diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 8ea360b0ff77..3301ef9c62c5 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -970,6 +970,7 @@ int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, 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); +int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status); bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in); int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in); int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in); diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index e7d9529822fa..67cb173a2f8e 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -211,6 +211,7 @@ struct tb_regs_switch_header { #define ROUTER_CS_9 0x09 #define ROUTER_CS_25 0x19 #define ROUTER_CS_26 0x1a +#define ROUTER_CS_26_OPCODE_MASK GENMASK(15, 0) #define ROUTER_CS_26_STATUS_MASK GENMASK(29, 24) #define ROUTER_CS_26_STATUS_SHIFT 24 #define ROUTER_CS_26_ONS BIT(30) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index f2583b4053e4..7bedebfef4f6 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -192,7 +192,9 @@ static int usb4_switch_op(struct tb_switch *sw, u16 opcode, u8 *status) if (val & ROUTER_CS_26_ONS) return -EOPNOTSUPP; - *status = (val & ROUTER_CS_26_STATUS_MASK) >> ROUTER_CS_26_STATUS_SHIFT; + if (status) + *status = (val & ROUTER_CS_26_STATUS_MASK) >> + ROUTER_CS_26_STATUS_SHIFT; return 0; } @@ -638,32 +640,71 @@ int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address, * @sw: USB4 router * * After the new NVM has been written via usb4_switch_nvm_write(), this - * function triggers NVM authentication process. If the authentication - * is successful the router is power cycled and the new NVM starts + * function triggers NVM authentication process. The router gets power + * cycled and if the authentication is successful the new NVM starts * running. In case of failure returns negative errno. + * + * The caller should call usb4_switch_nvm_authenticate_status() to read + * the status of the authentication after power cycle. It should be the + * first router operation to avoid the status being lost. */ int usb4_switch_nvm_authenticate(struct tb_switch *sw) { - u8 status = 0; int ret; - ret = usb4_switch_op(sw, USB4_SWITCH_OP_NVM_AUTH, &status); + ret = usb4_switch_op(sw, USB4_SWITCH_OP_NVM_AUTH, NULL); + switch (ret) { + /* + * The router is power cycled once NVM_AUTH is started so it is + * expected to get any of the following errors back. + */ + case -EACCES: + case -ENOTCONN: + case -ETIMEDOUT: + return 0; + + default: + return ret; + } +} + +/** + * usb4_switch_nvm_authenticate_status() - Read status of last NVM authenticate + * @sw: USB4 router + * @status: Status code of the operation + * + * The function checks if there is status available from the last NVM + * authenticate router operation. If there is status then %0 is returned + * and the status code is placed in @status. Returns negative errno in case + * of failure. + * + * Must be called before any other router operation. + */ +int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status) +{ + u16 opcode; + u32 val; + int ret; + + ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_26, 1); if (ret) return ret; - switch (status) { - case 0x0: - tb_sw_dbg(sw, "NVM authentication successful\n"); - return 0; - case 0x1: - return -EINVAL; - case 0x2: - return -EAGAIN; - case 0x3: - return -EOPNOTSUPP; - default: - return -EIO; + /* Check that the opcode is correct */ + opcode = val & ROUTER_CS_26_OPCODE_MASK; + if (opcode == USB4_SWITCH_OP_NVM_AUTH) { + if (val & ROUTER_CS_26_OV) + return -EBUSY; + if (val & ROUTER_CS_26_ONS) + return -EOPNOTSUPP; + + *status = (val & ROUTER_CS_26_STATUS_MASK) >> + ROUTER_CS_26_STATUS_SHIFT; + } else { + *status = 0; } + + return 0; } /**