Received: by 2002:a05:6358:3188:b0:123:57c1:9b43 with SMTP id q8csp3078589rwd; Wed, 14 Jun 2023 10:55:04 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6V9LWERYVjqxjZ+lBlWEjJBuDL5SF9aT+xzl8g/I4WBEYWVqOclhY0ZK2tHT7uU/ae6Jta X-Received: by 2002:aa7:d44e:0:b0:519:9b17:6938 with SMTP id q14-20020aa7d44e000000b005199b176938mr1399153edr.4.1686765303786; Wed, 14 Jun 2023 10:55:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1686765303; cv=none; d=google.com; s=arc-20160816; b=gGyQQ6tJF+GxWHHFzwIGU3Q6eDm9Tu+YG0rWg4tko9aXbMJFm4d9N/RS93H+vINV3i ClZAnaQ6Puzymdb4K55GIObNmk4ukOb1iaaa9WFYSduaGqC1fIRKIFtGuhibVnK2dhXj WprDC8dHWXKwMZkK/QWxZH9ev9bSzgLm/pHPtr7Gx1K9uXpNKWUAH61GiXBJnmzuQwgG DerkFq32bZGTOoqYhxwrEJdJUCddLD73Ent1VEvdsk6pboPQVe3+HXqYkqOWKzQNFGLQ QpHL/c4zcmf6vCaIpbO00/JEIegfsHqRkVyLJ8UfLgJNFEVBgSF7d+KNlUkXDf4m4GTD PGfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=aKCO7SvIPoKfptleCvN6fA0SeLpuTJoD1mqBPzY9FFo=; b=AQ/gsroGsbwVq9TPx6eTqDmS5ico33y8Ba9J9tXbcYAaoqMJTVtGFoSZsx+7OHpoZa Ga/Zoaawtc1O8R05dUVk6sLFUn9OuxzYLje/vlA1Br7p53ht/agoxyCnQ5gwk9zM7c1R zHLG4PqQAQ2fJxWwdA6OWHSrc/62zx9TwgtZfXGAgQtl4Z2pFHjZEM0H6lxljuLEag5Q 2behpoLGraW9+SipR9JttFuqovyaFu0Tz31PWZVSkR7TEW/hWCiWDwaat+NYEXOqf5Ju uZ2R/WjOkDHHeBpm3N0h6xngTfs1Dt1MOepnZ4fCmmFCQJisG/ZW7LqZ/CtwE+k7BHM0 0vDw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=nW7smaWZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a8-20020aa7d748000000b0051a1df527cesi501291eds.352.2023.06.14.10.54.38; Wed, 14 Jun 2023 10:55:03 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=nW7smaWZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237570AbjFNRSm (ORCPT + 99 others); Wed, 14 Jun 2023 13:18:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236305AbjFNRST (ORCPT ); Wed, 14 Jun 2023 13:18:19 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 87DC92686; Wed, 14 Jun 2023 10:18:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1686763094; x=1718299094; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=+EJu3qMR6xgl0nug2pw0HRRUOjawuGubA03KO1cVnIo=; b=nW7smaWZlQ108FofsYwC/PesF6toXlnM9bqwafOyygEMJYJJpZsrhuua k2uXqFK7vCnvupy7mkexWC4MaozVusIqdy4g3JV8pmNEG6oQYCLUcN2PM fvlvUBEL99BBBK9Nl2KLS6luHM58X0sD9KOni9QoxDmybv1pr9MPcoioF gheg+9tmE38WBPNiqIFkMu8pZalPAKeuiweFyEvYMrBrch3pADGs272E8 u8EKn8l/vFJM6p9xZ09D8SpSyVnbG68G0Tid8sd2kPGp8pvN0LjABMPH9 8Zmg7koFTwpR/XwX7e/XXo/mRtBkYEtW5iqVhorFwNL+2WB2bM7H8Z7uD A==; X-IronPort-AV: E=McAfee;i="6600,9927,10741"; a="362054389" X-IronPort-AV: E=Sophos;i="6.00,243,1681196400"; d="scan'208";a="362054389" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Jun 2023 10:18:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10741"; a="662470748" X-IronPort-AV: E=Sophos;i="6.00,243,1681196400"; d="scan'208";a="662470748" Received: from mahbubu1-mobl.amr.corp.intel.com (HELO [192.168.1.200]) ([10.209.44.245]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Jun 2023 10:18:09 -0700 From: Vishal Verma Date: Wed, 14 Jun 2023 11:17:43 -0600 Subject: [PATCH v4 4/4] tools/testing/cxl: add firmware update emulation to CXL memdevs MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20230602-vv-fw_update-v4-4-c6265bd7343b@intel.com> References: <20230602-vv-fw_update-v4-0-c6265bd7343b@intel.com> In-Reply-To: <20230602-vv-fw_update-v4-0-c6265bd7343b@intel.com> To: Alison Schofield , Ira Weiny , Dave Jiang , Ben Widawsky , Dan Williams Cc: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, Davidlohr Bueso , Jonathan Cameron , Russ Weight , Vishal Verma , Jonathan Cameron X-Mailer: b4 0.13-dev-02a79 X-Developer-Signature: v=1; a=openpgp-sha256; l=7811; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=+EJu3qMR6xgl0nug2pw0HRRUOjawuGubA03KO1cVnIo=; b=owGbwMvMwCXGf25diOft7jLG02pJDCmd3/xnPtpf4cTqV3e44msoj5k3V8WbY/fb2H9ysm/5W fC82mpVRykLgxgXg6yYIsvfPR8Zj8ltz+cJTHCEmcPKBDKEgYtTACZSHczwk7H/vdeXTZEXvoup clxj1PFxcuCZY108b3vxy4aTPxeftWX4n6a657+getoxtbfP1h5QnMW2R3zF0sq5wnneLEn/7t9 dxgQA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add emulation for the 'Get FW Info', 'Transfer FW', and 'Activate FW' CXL mailbox commands to the cxl_test emulated memdevs to enable end-to-end unit testing of a firmware update flow. For now, only advertise an 'offline activation' capability as that is all the CXL memdev driver currently implements. Add some canned values for the serial number fields, and create a platform device sysfs knob to calculate the sha256sum of the firmware image that was received, so a unit test can compare it with the original file that was uploaded. Cc: Davidlohr Bueso Cc: Jonathan Cameron Cc: Russ Weight Cc: Alison Schofield Cc: Ira Weiny Cc: Dave Jiang Cc: Ben Widawsky Cc: Dan Williams Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- tools/testing/cxl/test/mem.c | 160 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index 68668d8df1cd..1166f470e0c7 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -8,11 +8,14 @@ #include #include #include +#include #include #include "trace.h" #define LSA_SIZE SZ_128K +#define FW_SIZE SZ_64M +#define FW_SLOTS 3 #define DEV_SIZE SZ_2G #define EFFECT(x) (1U << x) @@ -72,6 +75,20 @@ static struct cxl_cel_entry mock_cel[] = { .opcode = cpu_to_le16(CXL_MBOX_OP_CLEAR_POISON), .effect = cpu_to_le16(EFFECT(DATA_CHANGE_IMMEDIATE)), }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_FW_INFO), + .effect = CXL_CMD_EFFECT_NONE, + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_TRANSFER_FW), + .effect = cpu_to_le16(EFFECT(CONF_CHANGE_COLD_RESET) | + EFFECT(BACKGROUND_OP)), + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_ACTIVATE_FW), + .effect = cpu_to_le16(EFFECT(CONF_CHANGE_COLD_RESET) | + EFFECT(CONF_CHANGE_IMMEDIATE)), + }, }; /* See CXL 2.0 Table 181 Get Health Info Output Payload */ @@ -123,6 +140,10 @@ struct mock_event_store { struct cxl_mockmem_data { void *lsa; + void *fw; + int fw_slot; + int fw_staged; + size_t fw_size; u32 security_state; u8 user_pass[NVDIMM_PASSPHRASE_LEN]; u8 master_pass[NVDIMM_PASSPHRASE_LEN]; @@ -1128,6 +1149,87 @@ static struct attribute *cxl_mock_mem_core_attrs[] = { }; ATTRIBUTE_GROUPS(cxl_mock_mem_core); +static int mock_fw_info(struct cxl_dev_state *cxlds, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); + struct cxl_mbox_get_fw_info fw_info = { + .num_slots = FW_SLOTS, + .slot_info = (mdata->fw_slot & 0x7) | + ((mdata->fw_staged & 0x7) << 3), + .activation_cap = 0, + }; + + strcpy(fw_info.slot_1_revision, "cxl_test_fw_001"); + strcpy(fw_info.slot_2_revision, "cxl_test_fw_002"); + strcpy(fw_info.slot_3_revision, "cxl_test_fw_003"); + strcpy(fw_info.slot_4_revision, ""); + + if (cmd->size_out < sizeof(fw_info)) + return -EINVAL; + + memcpy(cmd->payload_out, &fw_info, sizeof(fw_info)); + return 0; +} + +static int mock_transfer_fw(struct cxl_dev_state *cxlds, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_transfer_fw *transfer = cmd->payload_in; + struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); + void *fw = mdata->fw; + size_t offset, length; + + offset = le32_to_cpu(transfer->offset) * CXL_FW_TRANSFER_ALIGNMENT; + length = cmd->size_in - sizeof(*transfer); + if (offset + length > FW_SIZE) + return -EINVAL; + + switch (transfer->action) { + case CXL_FW_TRANSFER_ACTION_FULL: + if (offset != 0) + return -EINVAL; + fallthrough; + case CXL_FW_TRANSFER_ACTION_END: + if (transfer->slot == 0 || transfer->slot > FW_SLOTS) + return -EINVAL; + mdata->fw_size = offset + length; + break; + case CXL_FW_TRANSFER_ACTION_INITIATE: + case CXL_FW_TRANSFER_ACTION_CONTINUE: + break; + case CXL_FW_TRANSFER_ACTION_ABORT: + return 0; + default: + return -EINVAL; + } + + memcpy(fw + offset, transfer->data, length); + return 0; +} + +static int mock_activate_fw(struct cxl_dev_state *cxlds, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_activate_fw *activate = cmd->payload_in; + struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev); + + if (activate->slot == 0 || activate->slot > FW_SLOTS) + return -EINVAL; + + switch (activate->action) { + case CXL_FW_ACTIVATE_ONLINE: + mdata->fw_slot = activate->slot; + mdata->fw_staged = 0; + return 0; + case CXL_FW_ACTIVATE_OFFLINE: + mdata->fw_staged = activate->slot; + return 0; + } + + return -EINVAL; +} + static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) { struct device *dev = cxlds->dev; @@ -1194,6 +1296,15 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd * case CXL_MBOX_OP_CLEAR_POISON: rc = mock_clear_poison(cxlds, cmd); break; + case CXL_MBOX_OP_GET_FW_INFO: + rc = mock_fw_info(cxlds, cmd); + break; + case CXL_MBOX_OP_TRANSFER_FW: + rc = mock_transfer_fw(cxlds, cmd); + break; + case CXL_MBOX_OP_ACTIVATE_FW: + rc = mock_activate_fw(cxlds, cmd); + break; default: break; } @@ -1209,6 +1320,11 @@ static void label_area_release(void *lsa) vfree(lsa); } +static void fw_buf_release(void *buf) +{ + vfree(buf); +} + static bool is_rcd(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -1241,10 +1357,19 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) mdata->lsa = vmalloc(LSA_SIZE); if (!mdata->lsa) return -ENOMEM; + mdata->fw = vmalloc(FW_SIZE); + if (!mdata->fw) + return -ENOMEM; + mdata->fw_slot = 2; + rc = devm_add_action_or_reset(dev, label_area_release, mdata->lsa); if (rc) return rc; + rc = devm_add_action_or_reset(dev, fw_buf_release, mdata->fw); + if (rc) + return rc; + cxlds = cxl_dev_state_create(dev); if (IS_ERR(cxlds)) return PTR_ERR(cxlds); @@ -1286,6 +1411,10 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); + rc = cxl_memdev_setup_fw_upload(cxlds); + if (rc) + return rc; + cxl_mem_get_event_records(cxlds, CXLDEV_EVENT_STATUS_ALL); return 0; @@ -1324,9 +1453,40 @@ static ssize_t security_lock_store(struct device *dev, struct device_attribute * static DEVICE_ATTR_RW(security_lock); +static ssize_t fw_buf_checksum_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + u8 hash[SHA256_DIGEST_SIZE]; + unsigned char *hstr, *hptr; + struct sha256_state sctx; + ssize_t written = 0; + int i; + + sha256_init(&sctx); + sha256_update(&sctx, mdata->fw, mdata->fw_size); + sha256_final(&sctx, hash); + + hstr = kzalloc((SHA256_DIGEST_SIZE * 2) + 1, GFP_KERNEL); + if (!hstr) + return -ENOMEM; + + hptr = hstr; + for (i = 0; i < SHA256_DIGEST_SIZE; i++) + hptr += sprintf(hptr, "%02x", hash[i]); + + written = sysfs_emit(buf, "%s\n", hstr); + + kfree(hstr); + return written; +} + +static DEVICE_ATTR_RO(fw_buf_checksum); + static struct attribute *cxl_mock_mem_attrs[] = { &dev_attr_security_lock.attr, &dev_attr_event_trigger.attr, + &dev_attr_fw_buf_checksum.attr, NULL }; ATTRIBUTE_GROUPS(cxl_mock_mem); -- 2.40.1