From patchwork Mon Jun 5 20:21:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 13267993 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E2ADB261C9 for ; Mon, 5 Jun 2023 20:21:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685996472; x=1717532472; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=tt/zKtlu6wlEgPBhPI0yAHDizZsVDJdEUs6hJLl0aAA=; b=K655g/lTxNRhP0bal0E0sngyWWVHLrczpaAmKP8PX0v1M8KwapLDwSe6 LCosYVnespCscMjMJoidGPArr08ihoyGErUV35lsaPD5QlKjPhhhAZL4M zRmV+9LlyvpyK22vzRuelyEwBQe2qLIUnx3MHYyv9XOfmHzOVttCr3caC CBPtmEs6LIF/XKIVLcYvJQySBveIr5dU9AxQbRM8m9wXvpTD7mkI8oqs7 35A1LE+tPmjG2SrdJZngncSTtSW+pG7JN4fbvATjBt4nGl/kiBzWod37B sg2kfR8u9yCYwtUyF/jK6uNDGPsI+slbM7G96ptKr3vnfO+e0A7J755P5 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="336093172" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="336093172" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="832934299" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="832934299" Received: from kmsalzbe-mobl1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.209.52.9]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:10 -0700 From: Vishal Verma Date: Mon, 05 Jun 2023 14:21:03 -0600 Subject: [PATCH ndctl v2 1/5] cxl/memdev.c: allow filtering memdevs by bus Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v2-1-a778a15e860b@intel.com> References: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> In-Reply-To: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> To: linux-cxl@vger.kernel.org Cc: nvdimm@lists.linux.dev, Alison Schofield , Ira Weiny , Dave Jiang , Dan Williams , Vishal Verma X-Mailer: b4 0.13-dev-02a79 X-Developer-Signature: v=1; a=openpgp-sha256; l=6062; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=tt/zKtlu6wlEgPBhPI0yAHDizZsVDJdEUs6hJLl0aAA=; b=owGbwMvMwCXGf25diOft7jLG02pJDCl1zlsb1WTVI9a92Gy1/fJLripuW70Zael3LMMVNNkTb t/JCDzZUcrCIMbFICumyPJ3z0fGY3Lb83kCExxh5rAygQxh4OIUgInECzH8D+Q48a2V9cO5oo+G 5Zu3PPzk/ZZ7cs1mX8buJ44dYg6rmxj+14eeex3y3CizfurVr4Huup/mVptxPhf7sXvL4dNXZp4 M4QYA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF The family of memdev based commands implemented in memdev.c lacked an option to filter the operation by bus. Add a helper to filter memdevs by the bus they're under, and use it in memdev_action() which loops through the requested memdevs. Update the man pages for all the affected commands as well to include the bus filter option. Cc: Dan Williams Cc: Alison Schofield Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- Documentation/cxl/cxl-disable-memdev.txt | 2 ++ Documentation/cxl/cxl-enable-memdev.txt | 2 ++ Documentation/cxl/cxl-free-dpa.txt | 2 ++ Documentation/cxl/cxl-read-labels.txt | 2 ++ Documentation/cxl/cxl-reserve-dpa.txt | 2 ++ Documentation/cxl/cxl-set-partition.txt | 2 ++ Documentation/cxl/cxl-write-labels.txt | 3 +++ cxl/filter.h | 2 ++ cxl/filter.c | 19 +++++++++++++++++++ cxl/memdev.c | 4 ++++ 10 files changed, 40 insertions(+) diff --git a/Documentation/cxl/cxl-disable-memdev.txt b/Documentation/cxl/cxl-disable-memdev.txt index edd5385..d397802 100644 --- a/Documentation/cxl/cxl-disable-memdev.txt +++ b/Documentation/cxl/cxl-disable-memdev.txt @@ -18,6 +18,8 @@ OPTIONS :: include::memdev-option.txt[] +include::bus-option.txt[] + -f:: --force:: DANGEROUS: Override the safety measure that blocks attempts to disable diff --git a/Documentation/cxl/cxl-enable-memdev.txt b/Documentation/cxl/cxl-enable-memdev.txt index 088d5e0..5b5ed66 100644 --- a/Documentation/cxl/cxl-enable-memdev.txt +++ b/Documentation/cxl/cxl-enable-memdev.txt @@ -23,6 +23,8 @@ OPTIONS :: include::memdev-option.txt[] +include::bus-option.txt[] + -v:: Turn on verbose debug messages in the library (if libcxl was built with logging and debug enabled). diff --git a/Documentation/cxl/cxl-free-dpa.txt b/Documentation/cxl/cxl-free-dpa.txt index 73fb048..506fafd 100644 --- a/Documentation/cxl/cxl-free-dpa.txt +++ b/Documentation/cxl/cxl-free-dpa.txt @@ -24,6 +24,8 @@ OPTIONS :: include::memdev-option.txt[] +include::bus-option.txt[] + -d:: --decoder:: Specify the decoder to free. The CXL specification diff --git a/Documentation/cxl/cxl-read-labels.txt b/Documentation/cxl/cxl-read-labels.txt index 143f296..a96e7a4 100644 --- a/Documentation/cxl/cxl-read-labels.txt +++ b/Documentation/cxl/cxl-read-labels.txt @@ -20,6 +20,8 @@ OPTIONS ------- include::labels-options.txt[] +include::bus-option.txt[] + -o:: --output:: output file diff --git a/Documentation/cxl/cxl-reserve-dpa.txt b/Documentation/cxl/cxl-reserve-dpa.txt index 5e79ef2..58cc93e 100644 --- a/Documentation/cxl/cxl-reserve-dpa.txt +++ b/Documentation/cxl/cxl-reserve-dpa.txt @@ -24,6 +24,8 @@ OPTIONS :: include::memdev-option.txt[] +include::bus-option.txt[] + -d:: --decoder:: Specify the decoder to attempt the allocation. The CXL specification diff --git a/Documentation/cxl/cxl-set-partition.txt b/Documentation/cxl/cxl-set-partition.txt index f0126da..bed7f76 100644 --- a/Documentation/cxl/cxl-set-partition.txt +++ b/Documentation/cxl/cxl-set-partition.txt @@ -35,6 +35,8 @@ OPTIONS :: include::memdev-option.txt[] +include::bus-option.txt[] + -t:: --type=:: Type of partition, 'pmem' or 'ram' (volatile), to modify. diff --git a/Documentation/cxl/cxl-write-labels.txt b/Documentation/cxl/cxl-write-labels.txt index 75f42a5..8f2d139 100644 --- a/Documentation/cxl/cxl-write-labels.txt +++ b/Documentation/cxl/cxl-write-labels.txt @@ -21,6 +21,9 @@ not allow write access to the device's label data area. OPTIONS ------- include::labels-options.txt[] + +include::bus-option.txt[] + -i:: --input:: input file diff --git a/cxl/filter.h b/cxl/filter.h index c486514..595cde7 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -36,6 +36,8 @@ struct cxl_filter_params { struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, const char *__ident, const char *serials); +struct cxl_memdev *util_cxl_memdev_filter_by_bus(struct cxl_memdev *memdev, + const char *__ident); struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, const char *ident, const char *serial); diff --git a/cxl/filter.c b/cxl/filter.c index 90b13be..d2ab899 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -243,6 +243,25 @@ static struct cxl_port *util_cxl_port_filter_by_bus(struct cxl_port *port, return NULL; } +struct cxl_memdev *util_cxl_memdev_filter_by_bus(struct cxl_memdev *memdev, + const char *__ident) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_bus *bus; + + if (!__ident) + return memdev; + + cxl_bus_foreach(ctx, bus) { + if (!util_cxl_bus_filter(bus, __ident)) + continue; + if (bus == cxl_memdev_get_bus(memdev)) + return memdev; + } + + return NULL; +} + static struct cxl_decoder * util_cxl_decoder_filter_by_bus(struct cxl_decoder *decoder, const char *__ident) { diff --git a/cxl/memdev.c b/cxl/memdev.c index 0b3ad02..807e859 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -44,6 +44,8 @@ enum cxl_setpart_type { }; #define BASE_OPTIONS() \ +OPT_STRING('b', "bus", ¶m.bus, "bus name", \ + "Limit operation to the specified bus"), \ OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug"), \ OPT_BOOLEAN('S', "serial", ¶m.serial, "use serial numbers to id memdevs") @@ -753,6 +755,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, if (!util_cxl_memdev_filter(memdev, memdev_filter, serial_filter)) continue; + if (!util_cxl_memdev_filter_by_bus(memdev, param.bus)) + continue; found = true; if (action == action_write) { From patchwork Mon Jun 5 20:21:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 13267994 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7905E261CB for ; Mon, 5 Jun 2023 20:21:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685996473; x=1717532473; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=6joytIeXkxrGGxQ5Vs0F9aQ1D7WhdTy79hEq1u49ty4=; b=g5Nxz//RyTavuZswikRfT2m5uER7acOOk7F5bwwjRMdd/DWXl49nwPHU CGYPVd8B6xIfFpjdtYfgjVPxjDnVcfv0Yy1KWuBIrvpEOSmn5BKJu5hxp AcFuog41PGfy4wrkHgAdw+6+D2GYbNQNfYjxCwur0WHboUYMFVvgYcI5B u9wv8aXHSm+3EGqP2iJqRGFfHn7ZTnF4gGmFO+0a5/JHkRlEYtwSvdO8t o0mCzhsiJohYe1NpNRiB4r4nXCPiuQLZevmhs4mWqu2OIZivqOpqGU049 IcDl4VLOiDbJQaYlTmTZELV2p+cXMotcyG1aS230z4uqh3kQgRxbUL9Rw g==; X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="336093174" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="336093174" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="832934304" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="832934304" Received: from kmsalzbe-mobl1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.209.52.9]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:11 -0700 From: Vishal Verma Date: Mon, 05 Jun 2023 14:21:04 -0600 Subject: [PATCH ndctl v2 2/5] cxl/list: print firmware info in memdev listings Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v2-2-a778a15e860b@intel.com> References: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> In-Reply-To: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> To: linux-cxl@vger.kernel.org Cc: nvdimm@lists.linux.dev, Alison Schofield , Ira Weiny , Dave Jiang , Dan Williams , Vishal Verma X-Mailer: b4 0.13-dev-02a79 X-Developer-Signature: v=1; a=openpgp-sha256; l=9661; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=6joytIeXkxrGGxQ5Vs0F9aQ1D7WhdTy79hEq1u49ty4=; b=owGbwMvMwCXGf25diOft7jLG02pJDCl1zlsXzXrtflDv9Sw/ltlcP/8K/i2z/yufdEzY0Nhwx V216tU9HaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZjIw7UM/zOqTmnv+951kc9J fwPzU5Gcu43znrK+fHxZNtlZy6fKdhPD/2SR2o8cNkJxosVXXvjHyX7xu3/shUyXsVPcSlWP+/6 MnAA= X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Add libcxl APIs to send a 'Get Firmware Info' mailbox command, and accessors for its data fields. Add a json representation of this data, and add an option to cxl-list to display it under memdev listings. Cc: Dan Williams Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- cxl/lib/private.h | 21 +++++++++++++ cxl/lib/libcxl.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cxl/filter.h | 3 ++ cxl/libcxl.h | 7 +++++ cxl/json.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ cxl/list.c | 3 ++ cxl/lib/libcxl.sym | 6 ++++ 7 files changed, 214 insertions(+) diff --git a/cxl/lib/private.h b/cxl/lib/private.h index d648992..590d719 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -9,6 +9,7 @@ #include #include #include +#include #define CXL_EXPORT __attribute__ ((visibility("default"))) @@ -233,6 +234,26 @@ struct cxl_cmd_get_health_info { le32 pmem_errors; } __attribute__((packed)); +/* CXL 3.0 8.2.9.3.1 Get Firmware Info */ +struct cxl_cmd_get_fw_info { + u8 num_slots; + u8 slot_info; + u8 activation_cap; + u8 reserved[13]; + char slot_1_revision[0x10]; + char slot_2_revision[0x10]; + char slot_3_revision[0x10]; + char slot_4_revision[0x10]; +} __attribute__((packed)); + +#define CXL_FW_INFO_CUR_SLOT_MASK GENMASK(2, 0) +#define CXL_FW_INFO_NEXT_SLOT_MASK GENMASK(5, 3) +#define CXL_FW_INFO_NEXT_SLOT_SHIFT (3) +#define CXL_FW_INFO_HAS_LIVE_ACTIVATE BIT(0) + +#define CXL_FW_VERSION_STR_LEN 16 +#define CXL_FW_MAX_SLOTS 4 + /* CXL 3.0 8.2.9.8.3.2 Get Alert Configuration */ struct cxl_cmd_get_alert_config { u8 valid_alerts; diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 59e5bdb..90dce22 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -3917,6 +3917,96 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev, return cmd; } +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_fw_info(struct cxl_memdev *memdev) +{ + return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_FW_INFO); +} + +static struct cxl_cmd_get_fw_info *cmd_to_get_fw_info(struct cxl_cmd *cmd) +{ + if (cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_GET_FW_INFO)) + return NULL; + + return cmd->output_payload; +} + +CXL_EXPORT unsigned int cxl_cmd_fw_info_get_num_slots(struct cxl_cmd *cmd) +{ + struct cxl_cmd_get_fw_info *c = cmd_to_get_fw_info(cmd); + + if (!c) + return 0; + + return c->num_slots; +} + +CXL_EXPORT unsigned int cxl_cmd_fw_info_get_active_slot(struct cxl_cmd *cmd) +{ + struct cxl_cmd_get_fw_info *c = cmd_to_get_fw_info(cmd); + + if (!c) + return 0; + + return c->slot_info & CXL_FW_INFO_CUR_SLOT_MASK; +} + +CXL_EXPORT unsigned int cxl_cmd_fw_info_get_staged_slot(struct cxl_cmd *cmd) +{ + struct cxl_cmd_get_fw_info *c = cmd_to_get_fw_info(cmd); + + if (!c) + return 0; + + return (c->slot_info & CXL_FW_INFO_NEXT_SLOT_MASK) >> + CXL_FW_INFO_NEXT_SLOT_SHIFT; +} + +CXL_EXPORT bool cxl_cmd_fw_info_get_online_activate_capable(struct cxl_cmd *cmd) +{ + struct cxl_cmd_get_fw_info *c = cmd_to_get_fw_info(cmd); + + if (!c) + return false; + + return !!(c->activation_cap & CXL_FW_INFO_HAS_LIVE_ACTIVATE); +} + +CXL_EXPORT int cxl_cmd_fw_info_get_fw_ver(struct cxl_cmd *cmd, int slot, + char *buf, unsigned int len) +{ + struct cxl_cmd_get_fw_info *c = cmd_to_get_fw_info(cmd); + char *fw_ver; + + if (!c) + return -ENXIO; + if (!len) + return -EINVAL; + + switch(slot) { + case 1: + fw_ver = c->slot_1_revision; + break; + case 2: + fw_ver = c->slot_2_revision; + break; + case 3: + fw_ver = c->slot_3_revision; + break; + case 4: + fw_ver = c->slot_4_revision; + break; + default: + return -EINVAL; + } + + if (fw_ver[0] == 0) + return -ENOENT; + + memcpy(buf, fw_ver, min(len, (unsigned int)CXL_FW_VERSION_STR_LEN)); + + return 0; +} + CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd) { struct cxl_memdev *memdev = cmd->memdev; diff --git a/cxl/filter.h b/cxl/filter.h index 595cde7..3f65990 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -27,6 +27,7 @@ struct cxl_filter_params { bool human; bool health; bool partition; + bool fw; bool alert_config; bool dax; int verbose; @@ -81,6 +82,8 @@ static inline unsigned long cxl_filter_to_flags(struct cxl_filter_params *param) flags |= UTIL_JSON_TARGETS; if (param->partition) flags |= UTIL_JSON_PARTITION; + if (param->fw) + flags |= UTIL_JSON_FIRMWARE; if (param->alert_config) flags |= UTIL_JSON_ALERT_CONFIG; if (param->dax) diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 54d9f10..99e1b76 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -68,6 +68,13 @@ int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length, size_t offset); int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length, size_t offset); +struct cxl_cmd *cxl_cmd_new_get_fw_info(struct cxl_memdev *memdev); +unsigned int cxl_cmd_fw_info_get_num_slots(struct cxl_cmd *cmd); +unsigned int cxl_cmd_fw_info_get_active_slot(struct cxl_cmd *cmd); +unsigned int cxl_cmd_fw_info_get_staged_slot(struct cxl_cmd *cmd); +bool cxl_cmd_fw_info_get_online_activate_capable(struct cxl_cmd *cmd); +int cxl_cmd_fw_info_get_fw_ver(struct cxl_cmd *cmd, int slot, char *buf, + unsigned int len); #define cxl_memdev_foreach(ctx, memdev) \ for (memdev = cxl_memdev_get_first(ctx); \ diff --git a/cxl/json.c b/cxl/json.c index e87bdd4..e6bb061 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -12,6 +12,84 @@ #include "json.h" #include "../daxctl/json.h" +#define CXL_FW_VERSION_STR_LEN 16 +#define CXL_FW_MAX_SLOTS 4 + +static struct json_object *util_cxl_memdev_fw_to_json( + struct cxl_memdev *memdev, unsigned long flags) +{ + struct json_object *jobj; + struct json_object *jfw; + u32 field, num_slots; + struct cxl_cmd *cmd; + int rc, i; + + jfw = json_object_new_object(); + if (!jfw) + return NULL; + if (!memdev) + goto err_jobj; + + cmd = cxl_cmd_new_get_fw_info(memdev); + if (!cmd) + goto err_jobj; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) + goto err_cmd; + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) + goto err_cmd; + + /* fw_info fields */ + num_slots = cxl_cmd_fw_info_get_num_slots(cmd); + jobj = json_object_new_int(num_slots); + if (jobj) + json_object_object_add(jfw, "num_slots", jobj); + + field = cxl_cmd_fw_info_get_active_slot(cmd); + jobj = json_object_new_int(field); + if (jobj) + json_object_object_add(jfw, "active_slot", jobj); + + field = cxl_cmd_fw_info_get_staged_slot(cmd); + if (field > 0 && field <= num_slots) { + jobj = json_object_new_int(field); + if (jobj) + json_object_object_add(jfw, "staged_slot", jobj); + } + + rc = cxl_cmd_fw_info_get_online_activate_capable(cmd); + jobj = json_object_new_boolean(rc); + if (jobj) + json_object_object_add(jfw, "online_activate_capable", jobj); + + for (i = 1; i <= CXL_FW_MAX_SLOTS; i++) { + char fw_ver[CXL_FW_VERSION_STR_LEN + 1]; + char jkey[16]; + + rc = cxl_cmd_fw_info_get_fw_ver(cmd, i, fw_ver, + CXL_FW_VERSION_STR_LEN); + if (rc) + continue; + fw_ver[CXL_FW_VERSION_STR_LEN] = 0; + snprintf(jkey, 16, "slot_%d_version", i); + jobj = json_object_new_string(fw_ver); + if (jobj) + json_object_object_add(jfw, jkey, jobj); + } + + cxl_cmd_unref(cmd); + return jfw; + +err_cmd: + cxl_cmd_unref(cmd); +err_jobj: + json_object_put(jfw); + return NULL; + +} + static struct json_object *util_cxl_memdev_health_to_json( struct cxl_memdev *memdev, unsigned long flags) { @@ -552,6 +630,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, json_object_object_add(jdev, "partition_info", jobj); } + if (flags & UTIL_JSON_FIRMWARE) { + jobj = util_cxl_memdev_fw_to_json(memdev, flags); + if (jobj) + json_object_object_add(jdev, "firmware", jobj); + } + json_object_set_userdata(jdev, memdev, NULL); return jdev; } diff --git a/cxl/list.c b/cxl/list.c index c01154e..93ba51e 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -53,6 +53,8 @@ static const struct option options[] = { "include memory device health information"), OPT_BOOLEAN('I', "partition", ¶m.partition, "include memory device partition information"), + OPT_BOOLEAN('F', "firmware", ¶m.fw, + "include memory device firmware information"), OPT_BOOLEAN('A', "alert-config", ¶m.alert_config, "include alert configuration information"), OPT_INCR('v', "verbose", ¶m.verbose, "increase output detail"), @@ -116,6 +118,7 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) case 3: param.health = true; param.partition = true; + param.fw = true; param.alert_config = true; param.dax = true; /* fallthrough */ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 1c6177c..16a8671 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -248,4 +248,10 @@ global: cxl_region_get_mode; cxl_decoder_create_ram_region; cxl_region_get_daxctl_region; + cxl_cmd_new_get_fw_info; + cxl_cmd_fw_info_get_num_slots; + cxl_cmd_fw_info_get_active_slot; + cxl_cmd_fw_info_get_staged_slot; + cxl_cmd_fw_info_get_online_activate_capable; + cxl_cmd_fw_info_get_fw_ver; } LIBCXL_4; From patchwork Mon Jun 5 20:21:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 13267995 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 171E4DDC0 for ; Mon, 5 Jun 2023 20:21:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685996474; x=1717532474; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=J8Nfv+kzAtWjVhkwwH6Z8qaOCS1RLetx48jsfYGvsG8=; b=j9qlG6HM9I+psDTse1nP9V65m+JPRxzGkqkinrmAr3qzE2PlWOuJXnCE vjgX1iNcrQHYOOlb/l7zCdoFNnlzNV03ZD+fbeYp7ZgaE2fvfuOqXSKsH LG8uLrTar2UVp3c182LtBQaOUKdbKV8dhZLlCVGk5Hs+gPkwcjQke+iaT YQnBAe9/VH8D6d3HmI+NTeZV2MEAiKYr06jUjrF6Av8C8/BmJ/ko7ovy/ 26DB6JdLOQEUyWQtwymspfK5R/jQYB0WE+sCxXKsKx6u2tumhFi7XbhYW X0YfWpJE+kQb4l0bLv3oQd7XkDYZ/INMpvvPzrbmNPzsBjmew1lV2EYV0 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="336093178" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="336093178" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="832934310" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="832934310" Received: from kmsalzbe-mobl1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.209.52.9]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:11 -0700 From: Vishal Verma Date: Mon, 05 Jun 2023 14:21:05 -0600 Subject: [PATCH ndctl v2 3/5] cxl/fw_loader: add APIs to get current state of the FW loader mechanism Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v2-3-a778a15e860b@intel.com> References: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> In-Reply-To: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> To: linux-cxl@vger.kernel.org Cc: nvdimm@lists.linux.dev, Alison Schofield , Ira Weiny , Dave Jiang , Dan Williams , Vishal Verma X-Mailer: b4 0.13-dev-02a79 X-Developer-Signature: v=1; a=openpgp-sha256; l=7944; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=J8Nfv+kzAtWjVhkwwH6Z8qaOCS1RLetx48jsfYGvsG8=; b=owGbwMvMwCXGf25diOft7jLG02pJDCl1ztvEwrOKv8/3vKj87ufE41seSE28esP6t7DWJN4Sj q0Z6x2jO0pZGMS4GGTFFFn+7vnIeExuez5PYIIjzBxWJpAhDFycAjCRQC9Ghrb/Ejbz49du/t4y zXyWEIPuMs20DNF9Lod0paXqNKS2ODIyPPZ6rDr118Hcwryiuti/O+3ylRSW31z5J3Ei/421H3f 2cQAA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Add a way to interface with the firmware loader mechanism for cxl memdevs. Add APIs to retrieve the current status of the fw loader, and the remaining size if a fw upload is in progress. Display these in the 'firmware' section of memdev listings. Cc: Dan Williams Signed-off-by: Vishal Verma --- cxl/lib/private.h | 10 ++++++ cxl/lib/libcxl.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cxl/libcxl.h | 27 ++++++++++++++++ cxl/json.c | 13 ++++++++ cxl/lib/libcxl.sym | 2 ++ 5 files changed, 147 insertions(+) diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 590d719..95e0c43 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -20,6 +20,15 @@ struct cxl_pmem { char *dev_path; }; +struct cxl_fw_loader { + char *dev_path; + char *loading; + char *data; + char *remaining; + char *cancel; + char *status; +}; + struct cxl_endpoint; struct cxl_memdev { int id, major, minor; @@ -39,6 +48,7 @@ struct cxl_memdev { struct cxl_pmem *pmem; unsigned long long serial; struct cxl_endpoint *endpoint; + struct cxl_fw_loader *fwl; }; struct cxl_dport { diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 90dce22..5f74138 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -63,12 +63,25 @@ static void free_pmem(struct cxl_pmem *pmem) } } +static void free_fwl(struct cxl_fw_loader *fwl) +{ + if (fwl) { + free(fwl->loading); + free(fwl->data); + free(fwl->remaining); + free(fwl->cancel); + free(fwl->status); + free(fwl); + } +} + static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) { if (head) list_del_from(head, &memdev->list); kmod_module_unref(memdev->module); free_pmem(memdev->pmem); + free_fwl(memdev->fwl); free(memdev->firmware_version); free(memdev->dev_buf); free(memdev->dev_path); @@ -1174,6 +1187,40 @@ static void *add_cxl_pmem(void *parent, int id, const char *br_base) return NULL; } +static int add_cxl_memdev_fwl(struct cxl_memdev *memdev, + const char *cxlmem_base) +{ + const char *devname = cxl_memdev_get_devname(memdev); + struct cxl_fw_loader *fwl; + + fwl = calloc(1, sizeof(*fwl)); + if (!fwl) + return -ENOMEM; + + if (asprintf(&fwl->loading, "%s/firmware/%s/loading", cxlmem_base, + devname) < 0) + goto err_read; + if (asprintf(&fwl->data, "%s/firmware/%s/data", cxlmem_base, devname) < + 0) + goto err_read; + if (asprintf(&fwl->remaining, "%s/firmware/%s/remaining_size", + cxlmem_base, devname) < 0) + goto err_read; + if (asprintf(&fwl->cancel, "%s/firmware/%s/cancel", cxlmem_base, + devname) < 0) + goto err_read; + if (asprintf(&fwl->status, "%s/firmware/%s/status", cxlmem_base, + devname) < 0) + goto err_read; + + memdev->fwl = fwl; + return 0; + + err_read: + free_fwl(fwl); + return -ENOMEM; +} + static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) { const char *devname = devpath_to_devname(cxlmem_base); @@ -1263,6 +1310,9 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_pmem); + if (add_cxl_memdev_fwl(memdev, cxlmem_base)) + goto err_read; + cxl_memdev_foreach(ctx, memdev_dup) if (memdev_dup->id == memdev->id) { free_memdev(memdev, NULL); @@ -1373,6 +1423,51 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev return memdev->firmware_version; } +static enum cxl_fwl_status cxl_fwl_get_status(struct cxl_memdev *memdev) +{ + const char *devname = cxl_memdev_get_devname(memdev); + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_fw_loader *fwl = memdev->fwl; + char buf[SYSFS_ATTR_SIZE]; + int rc; + + rc = sysfs_read_attr(ctx, fwl->status, buf); + if (rc < 0) { + err(ctx, "%s: failed to get fw loader status (%s)\n", devname, + strerror(-rc)); + return CXL_FWL_STATUS_UNKNOWN; + } + + return cxl_fwl_status_from_ident(buf); +} + +CXL_EXPORT bool cxl_memdev_fw_update_in_progress(struct cxl_memdev *memdev) +{ + int status = cxl_fwl_get_status(memdev); + + if (status == CXL_FWL_STATUS_IDLE) + return false; + return true; +} + +CXL_EXPORT size_t cxl_memdev_fw_update_get_remaining(struct cxl_memdev *memdev) +{ + const char *devname = cxl_memdev_get_devname(memdev); + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_fw_loader *fwl = memdev->fwl; + char buf[SYSFS_ATTR_SIZE]; + int rc; + + rc = sysfs_read_attr(ctx, fwl->remaining, buf); + if (rc < 0) { + err(ctx, "%s: failed to get fw loader remaining size (%s)\n", + devname, strerror(-rc)); + return 0; + } + + return strtoull(buf, NULL, 0); +} + static void bus_invalidate(struct cxl_bus *bus) { struct cxl_ctx *ctx = cxl_bus_get_ctx(bus); diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 99e1b76..7509abe 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -33,6 +33,31 @@ void *cxl_get_userdata(struct cxl_ctx *ctx); void cxl_set_private_data(struct cxl_ctx *ctx, void *data); void *cxl_get_private_data(struct cxl_ctx *ctx); +enum cxl_fwl_status { + CXL_FWL_STATUS_UNKNOWN, + CXL_FWL_STATUS_IDLE, + CXL_FWL_STATUS_RECEIVING, + CXL_FWL_STATUS_PREPARING, + CXL_FWL_STATUS_TRANSFERRING, + CXL_FWL_STATUS_PROGRAMMING, +}; + +static inline enum cxl_fwl_status cxl_fwl_status_from_ident(char *status) +{ + if (strcmp(status, "idle") == 0) + return CXL_FWL_STATUS_IDLE; + if (strcmp(status, "receiving") == 0) + return CXL_FWL_STATUS_RECEIVING; + if (strcmp(status, "preparing") == 0) + return CXL_FWL_STATUS_PREPARING; + if (strcmp(status, "transferring") == 0) + return CXL_FWL_STATUS_TRANSFERRING; + if (strcmp(status, "programming") == 0) + return CXL_FWL_STATUS_PROGRAMMING; + + return CXL_FWL_STATUS_UNKNOWN; +} + struct cxl_memdev; struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx); struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); @@ -48,6 +73,8 @@ struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev); const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev); +bool cxl_memdev_fw_update_in_progress(struct cxl_memdev *memdev); +size_t cxl_memdev_fw_update_get_remaining(struct cxl_memdev *memdev); /* ABI spelling mistakes are forever */ static inline const char *cxl_memdev_get_firmware_version( diff --git a/cxl/json.c b/cxl/json.c index e6bb061..5dc0bd3 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -22,6 +22,7 @@ static struct json_object *util_cxl_memdev_fw_to_json( struct json_object *jfw; u32 field, num_slots; struct cxl_cmd *cmd; + size_t remaining; int rc, i; jfw = json_object_new_object(); @@ -79,6 +80,18 @@ static struct json_object *util_cxl_memdev_fw_to_json( json_object_object_add(jfw, jkey, jobj); } + rc = cxl_memdev_fw_update_in_progress(memdev); + jobj = json_object_new_boolean(rc); + if (jobj) + json_object_object_add(jfw, "fw_update_in_progress", jobj); + + if (rc == true) { + remaining = cxl_memdev_fw_update_get_remaining(memdev); + jobj = util_json_object_size(remaining, flags); + if (jobj) + json_object_object_add(jfw, "remaining_size", jobj); + } + cxl_cmd_unref(cmd); return jfw; diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 16a8671..9438877 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -254,4 +254,6 @@ global: cxl_cmd_fw_info_get_staged_slot; cxl_cmd_fw_info_get_online_activate_capable; cxl_cmd_fw_info_get_fw_ver; + cxl_memdev_fw_update_in_progress; + cxl_memdev_fw_update_get_remaining; } LIBCXL_4; From patchwork Mon Jun 5 20:21:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 13267996 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9E17E261D4 for ; Mon, 5 Jun 2023 20:21:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685996474; x=1717532474; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=3erz4vNorrE9D3nURvJ2i5Dl9zxYwU7cP6Q27FVxDF0=; b=KzbnlZvI0TCScBOozypC3HRtXQs1PqZMCsCJnn3pPwOWpMq18X3ZnzPF UXX/Bn7MceZCD3/j/3kn+j6Aj2uDw5UQYcSm9C/jllk564fT1/KUuf3MP f1+8RdQkZjWsZ/G3OB05j8QcpZEkDjIKobtbjb+TKCTzKjNoD7jH+RQkz QWHZlO0wKDvccCJFWK3VV7YaSxPDmLRJF3qFacuIIKbyyOlAwEaQIt0QB T134nVNNTBqGZ5k5vSt29oF980RAyY58/+33uAkJ5Tz8Qj2KiDwm9SPC3 vqmMUfah1CFDA80ZiZR7SjCUO5/4z1zyF6blO8cVC3ztZPRj/3D5oGXGs w==; X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="336093182" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="336093182" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="832934317" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="832934317" Received: from kmsalzbe-mobl1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.209.52.9]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:11 -0700 From: Vishal Verma Date: Mon, 05 Jun 2023 14:21:06 -0600 Subject: [PATCH ndctl v2 4/5] cxl: add an update-firmware command Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v2-4-a778a15e860b@intel.com> References: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> In-Reply-To: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> To: linux-cxl@vger.kernel.org Cc: nvdimm@lists.linux.dev, Alison Schofield , Ira Weiny , Dave Jiang , Dan Williams , Vishal Verma X-Mailer: b4 0.13-dev-02a79 X-Developer-Signature: v=1; a=openpgp-sha256; l=13427; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=3erz4vNorrE9D3nURvJ2i5Dl9zxYwU7cP6Q27FVxDF0=; b=owGbwMvMwCXGf25diOft7jLG02pJDCl1ztv+xD3I5Y2cLcqg7Pww239VO2PTxxdtmwrWXN1zZ d++4L5JHaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZiIwTqGf9ZiWxN2Nz1fpN0h vqs2fPP+vW+eeUt/9JspaMZwTmXGAn6Gf7oiuTpNVt+/u67+d15W+3qjSfHXjpRlp6em/2jesm0 uJz8A X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Add a new cxl-update-firmware command to initiate a firmware update on a given memdev. This allows using a specified file to pass in as the firmware binary for one or more memdevs, allows for a blocking mode, where the command only exits after the update is complete for every specified memdev, and includes an option to cancel an in-progress update. Add the supporting libcxl APIs for the above functions as well. Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- Documentation/cxl/cxl-update-firmware.txt | 85 ++++++++++++++++++++++ cxl/lib/private.h | 5 ++ cxl/lib/libcxl.c | 114 ++++++++++++++++++++++++++++++ cxl/builtin.h | 1 + cxl/libcxl.h | 2 + cxl/cxl.c | 1 + cxl/memdev.c | 73 ++++++++++++++++++- Documentation/cxl/meson.build | 1 + cxl/lib/libcxl.sym | 2 + 9 files changed, 283 insertions(+), 1 deletion(-) diff --git a/Documentation/cxl/cxl-update-firmware.txt b/Documentation/cxl/cxl-update-firmware.txt new file mode 100644 index 0000000..b7342aa --- /dev/null +++ b/Documentation/cxl/cxl-update-firmware.txt @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-update-firmware(1) +====================== + +NAME +---- +cxl-update-firmware - update the firmware on a CXL memdev + +SYNOPSIS +-------- +[verse] +'cxl update-firmware [..] []' + +DESCRIPTION +----------- + +Update the firmware on one or more CXL mem devices. The mem devices +must support the set of firmware related mailbox commands. + +This command doesn't directly issue the transfer / activate firmware +mailbox commands. Instead, the kernel's firmware loader facility is +used to provide the kernel with the data, and the kernel handles +performing the actual update while also managing time slicing the +transfer w.r.t. other background commands. + +EXAMPLE +------- +---- +# cxl update-firmware mem0 -F firmware.bin -w +[ + { + "memdev":"mem0", + "pmem_size":1073741824, + "ram_size":1073741824, + "serial":0, + "numa_node":0, + "host":"cxl_mem.0", + "firmware":{ + "num_slots":3, + "active_slot":2, + "online_activate_capable":false, + "slot_1_version":"cxl_test_fw_001", + "slot_2_version":"cxl_test_fw_002", + "slot_3_version":"cxl_test_new_fw", + "fw_update_in_progress":false + } + } +] +firmware update completed on 1 mem device +---- + +OPTIONS +------- + +include::bus-option.txt[] + +-F:: +--firmware-file:: + Firmware image file to use for the update. + +-c:: +--cancel:: + Attempt to abort an in-progress firmware update. This may + fail depending on what stage the update process is in. + +-w:: +--wait:: + By default, the update-firmware command only initiates the + firmware update, and returns, while the update operation + happens asynchronously in the background. This option makes + the firmware update command synchronous by waiting for it to + complete before returning. + + If --wait is passed in without an accompanying firmware-file, + it will initiate a wait on any current in-progress firmware + updates, and then return. + +include::verbose-option.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-list[1], diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 95e0c43..6388534 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -29,6 +29,11 @@ struct cxl_fw_loader { char *status; }; +enum cxl_fwl_loading { + CXL_FWL_LOADING_END = 0, + CXL_FWL_LOADING_START, +}; + struct cxl_endpoint; struct cxl_memdev { int id, major, minor; diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 5f74138..8094cf8 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1468,6 +1469,119 @@ CXL_EXPORT size_t cxl_memdev_fw_update_get_remaining(struct cxl_memdev *memdev) return strtoull(buf, NULL, 0); } +static int cxl_memdev_fwl_set_loading(struct cxl_memdev *memdev, + enum cxl_fwl_loading loadval) +{ + const char *devname = cxl_memdev_get_devname(memdev); + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_fw_loader *fwl = memdev->fwl; + char buf[SYSFS_ATTR_SIZE]; + int rc; + + sprintf(buf, "%d\n", loadval); + rc = sysfs_write_attr(ctx, fwl->loading, buf); + if (rc < 0) { + err(ctx, "%s: failed to trigger fw loading to %d (%s)\n", + devname, loadval, strerror(-rc)); + return rc; + } + + return 0; +} + +static int cxl_memdev_fwl_copy_data(struct cxl_memdev *memdev, void *fw_buf, + size_t size) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_fw_loader *fwl = memdev->fwl; + FILE *fwl_data; + size_t rw_len; + int rc = 0; + + fwl_data = fopen(fwl->data, "w"); + if (!fwl_data) { + err(ctx, "failed to open: %s: (%s)\n", fwl->data, + strerror(errno)); + return -errno; + } + + rw_len = fwrite(fw_buf, 1, size, fwl_data); + if (rw_len != size) { + rc = -ENXIO; + goto out_close; + } + fflush(fwl_data); + +out_close: + fclose(fwl_data); + return rc; +} + +CXL_EXPORT int cxl_memdev_update_fw(struct cxl_memdev *memdev, + const char *fw_path) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct stat s; + int f_in, rc; + void *fw_buf; + + f_in = open(fw_path, O_RDONLY); + if (f_in < 0) { + err(ctx, "failed to open: %s: (%s)\n", fw_path, + strerror(errno)); + return -errno; + } + + rc = fstat(f_in, &s); + if (rc < 0) { + err(ctx, "failed to stat: %s: (%s)\n", fw_path, + strerror(errno)); + rc = -errno; + goto out_close; + } + + fw_buf = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, f_in, 0); + if (fw_buf == MAP_FAILED) { + err(ctx, "failed to map: %s: (%s)\n", fw_path, + strerror(errno)); + rc = -errno; + goto out_close; + } + + rc = cxl_memdev_fwl_set_loading(memdev, CXL_FWL_LOADING_START); + if (rc) + goto out_unmap; + + rc = cxl_memdev_fwl_copy_data(memdev, fw_buf, s.st_size); + if (rc) + goto out_unmap; + + rc = cxl_memdev_fwl_set_loading(memdev, CXL_FWL_LOADING_END); + +out_unmap: + munmap(fw_buf, s.st_size); +out_close: + close(f_in); + return rc; +} + +CXL_EXPORT int cxl_memdev_cancel_fw_update(struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_fw_loader *fwl = memdev->fwl; + int rc; + + if (!cxl_memdev_fw_update_in_progress(memdev) && + cxl_memdev_fw_update_get_remaining(memdev) == 0) + return -ENXIO; + + rc = sysfs_write_attr(ctx, fwl->cancel, "1\n"); + if (rc < 0) + return rc; + + return 0; +} + static void bus_invalidate(struct cxl_bus *bus) { struct cxl_ctx *ctx = cxl_bus_get_ctx(bus); diff --git a/cxl/builtin.h b/cxl/builtin.h index 9baa43b..3ec6c6c 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -14,6 +14,7 @@ int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_reserve_dpa(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_free_dpa(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_update_fw(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx); diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 7509abe..2ffb39c 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -75,6 +75,8 @@ unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev); const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev); bool cxl_memdev_fw_update_in_progress(struct cxl_memdev *memdev); size_t cxl_memdev_fw_update_get_remaining(struct cxl_memdev *memdev); +int cxl_memdev_update_fw(struct cxl_memdev *memdev, const char *fw_path); +int cxl_memdev_cancel_fw_update(struct cxl_memdev *memdev); /* ABI spelling mistakes are forever */ static inline const char *cxl_memdev_get_firmware_version( diff --git a/cxl/cxl.c b/cxl/cxl.c index 3be7026..e1524b8 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -68,6 +68,7 @@ static struct cmd_struct commands[] = { { "enable-memdev", .c_fn = cmd_enable_memdev }, { "reserve-dpa", .c_fn = cmd_reserve_dpa }, { "free-dpa", .c_fn = cmd_free_dpa }, + { "update-firmware", .c_fn = cmd_update_fw }, { "disable-port", .c_fn = cmd_disable_port }, { "enable-port", .c_fn = cmd_enable_port }, { "set-partition", .c_fn = cmd_set_partition }, diff --git a/cxl/memdev.c b/cxl/memdev.c index 807e859..1ad871a 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -23,14 +23,18 @@ struct action_context { }; static struct parameters { + const char *bus; const char *outfile; const char *infile; + const char *fw_file; unsigned len; unsigned offset; bool verbose; bool serial; bool force; bool align; + bool cancel; + bool wait; const char *type; const char *size; const char *decoder_filter; @@ -87,6 +91,14 @@ OPT_STRING('t', "type", ¶m.type, "type", \ OPT_BOOLEAN('f', "force", ¶m.force, \ "Attempt 'expected to fail' operations") +#define FW_OPTIONS() \ +OPT_STRING('F', "firmware-file", ¶m.fw_file, "firmware-file", \ + "firmware image file to use for the update"), \ +OPT_BOOLEAN('c', "cancel", ¶m.cancel, \ + "attempt to abort an in-progress firmware update"), \ +OPT_BOOLEAN('w', "wait", ¶m.wait, \ + "wait for firmware update to complete before returning") + static const struct option read_options[] = { BASE_OPTIONS(), LABEL_OPTIONS(), @@ -137,6 +149,12 @@ static const struct option free_dpa_options[] = { OPT_END(), }; +static const struct option update_fw_options[] = { + BASE_OPTIONS(), + FW_OPTIONS(), + OPT_END(), +}; + enum reserve_dpa_mode { DPA_ALLOC, DPA_FREE, @@ -655,6 +673,39 @@ out_err: return rc; } +static int action_update_fw(struct cxl_memdev *memdev, + struct action_context *actx) +{ + const char *devname = cxl_memdev_get_devname(memdev); + struct json_object *jmemdev; + unsigned long flags; + int rc; + + if (param.cancel) + return cxl_memdev_cancel_fw_update(memdev); + + if (param.fw_file) { + rc = cxl_memdev_update_fw(memdev, param.fw_file); + if (rc) + log_err(&ml, "%s error: %s\n", devname, strerror(-rc)); + } + + if (param.wait) { + while (cxl_memdev_fw_update_in_progress(memdev) || + cxl_memdev_fw_update_get_remaining(memdev) > 0) + sleep(1); + } + + flags = UTIL_JSON_FIRMWARE; + if (actx->f_out == stdout && isatty(1)) + flags |= UTIL_JSON_HUMAN; + jmemdev = util_cxl_memdev_to_json(memdev, flags); + if (actx->jdevs && jmemdev) + json_object_array_add(actx->jdevs, jmemdev); + + return rc; +} + static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, int (*action)(struct cxl_memdev *memdev, struct action_context *actx), @@ -698,7 +749,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, } if (action == action_setpartition || action == action_reserve_dpa || - action == action_free_dpa) + action == action_free_dpa || action == action_update_fw) actx.jdevs = json_object_new_array(); if (err == argc) { @@ -897,3 +948,23 @@ int cmd_free_dpa(int argc, const char **argv, struct cxl_ctx *ctx) return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_update_fw(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int count = memdev_action( + argc, argv, ctx, action_update_fw, update_fw_options, + "cxl update-firmware [..] []"); + const char *op_string; + + if (param.cancel) + op_string = "cancelled"; + else if (param.wait) + op_string = "completed"; + else + op_string = "started"; + + log_info(&ml, "firmware update %s on %d mem device%s\n", op_string, + count >= 0 ? count : 0, count > 1 ? "s" : ""); + + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index a6d77ab..c553357 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -46,6 +46,7 @@ cxl_manpages = [ 'cxl-enable-region.txt', 'cxl-destroy-region.txt', 'cxl-monitor.txt', + 'cxl-update-firmware.txt', ] foreach man : cxl_manpages diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 9438877..ce0cb7f 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -256,4 +256,6 @@ global: cxl_cmd_fw_info_get_fw_ver; cxl_memdev_fw_update_in_progress; cxl_memdev_fw_update_get_remaining; + cxl_memdev_update_fw; + cxl_memdev_cancel_fw_update; } LIBCXL_4; From patchwork Mon Jun 5 20:21:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 13267997 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 75421261D7 for ; Mon, 5 Jun 2023 20:21:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685996475; x=1717532475; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=LlVEQrDPE8IPCzrGqxiaHepxm+PhW003Qczq56Mw48s=; b=M9MsuDsJWmFTuM8tlLW5e/ioF0SEsyjCivp90M6DMNLDqr77yBgJiP/S kydBXh5UXMWZQNAXJNOUg/5RZD2V0TOy1/HhXVU+Aa19AefatRPTMcJ9c MftkIOIoy4Gt8aC0fj3aTAV/z84bqMgjz27vZtkVpoFEq0ld+4gQ3Bql+ 9GuJxMOu2LLasTU7oknM1o4jYafxMW8ho+Lmn9lb0ZXdFUVSUzhPISl4u wO9A8l3rZ4TOTZL59xqEAwZtRho9wXSXMML4fcN+Eg2HDoO9THHuslTJp FE9l3IIlJfROcBOyJu/8ofZFRhAjQnPErcC2QvovmUT9KhG2HmO4moavR Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="336093186" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="336093186" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10732"; a="832934323" X-IronPort-AV: E=Sophos;i="6.00,218,1681196400"; d="scan'208";a="832934323" Received: from kmsalzbe-mobl1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.209.52.9]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 13:21:12 -0700 From: Vishal Verma Date: Mon, 05 Jun 2023 14:21:07 -0600 Subject: [PATCH ndctl v2 5/5] test/cxl-update-firmware: add a unit test for firmware update Precedence: bulk X-Mailing-List: nvdimm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v2-5-a778a15e860b@intel.com> References: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> In-Reply-To: <20230405-vv-fw_update-v2-0-a778a15e860b@intel.com> To: linux-cxl@vger.kernel.org Cc: nvdimm@lists.linux.dev, Alison Schofield , Ira Weiny , Dave Jiang , Dan Williams , Vishal Verma X-Mailer: b4 0.13-dev-02a79 X-Developer-Signature: v=1; a=openpgp-sha256; l=5613; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=LlVEQrDPE8IPCzrGqxiaHepxm+PhW003Qczq56Mw48s=; b=owGbwMvMwCXGf25diOft7jLG02pJDCl1ztteWJkL7XxhwWdldGPmOp9Ven/VdCzc4qLyj12bd 67Jty2so5SFQYyLQVZMkeXvno+Mx+S25/MEJjjCzGFlAhnCwMUpABN5H8zwTyUkY+E9myXymT3d Xh/K/MKOzT0z41Sn8hE1A20pb8NrLYwMF9vZ53qtYT2zd+/WJ83ZSpr6qxqXbJ7WGPPZendzb/F MbgA= X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Add a unit test to exercise the different operating modes of the cxl-update-firmware command. Perform an update synchronously, asynchronously, on multiple devices, and attempt cancellation of an in-progress update. Cc: Dan Williams Reviewed-by: Dave Jiang Signed-off-by: Vishal Verma --- test/cxl-update-firmware.sh | 195 ++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 2 + 2 files changed, 197 insertions(+) diff --git a/test/cxl-update-firmware.sh b/test/cxl-update-firmware.sh new file mode 100755 index 0000000..c6cd742 --- /dev/null +++ b/test/cxl-update-firmware.sh @@ -0,0 +1,195 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2023 Intel Corporation. All rights reserved. + +. $(dirname $0)/common + +rc=77 + +set -ex + +trap 'err $LINENO' ERR + +check_prereq "jq" +check_prereq "dd" +check_prereq "sha256sum" + +modprobe -r cxl_test +modprobe cxl_test +rc=1 + +mk_fw_file() +{ + size="$1" + + if [[ ! $size ]]; then + err "$LINENO" + fi + if (( size > 64 )); then + err "$LINENO" + fi + + fw_file="$(mktemp -p /tmp fw_file_XXXX)" + dd if=/dev/urandom of="$fw_file" bs=1M count="$size" + echo "$fw_file" +} + +find_memdevs() +{ + count="$1" + + if [[ ! $count ]]; then + count=1 + fi + + "$CXL" list -M -b "$CXL_TEST_BUS" \ + | jq -r '.[] | select(.host | startswith("cxl_mem.")) | .memdev' \ + | head -"$count" +} + +do_update_fw() +{ + "$CXL" update-firmware -b "$CXL_TEST_BUS" "$@" +} + +wait_complete() +{ + mem="$1" # single memdev, not a list + max_wait="$2" # in seconds + waited=0 + + while true; do + json="$("$CXL" list -m "$mem" -F)" + in_prog="$(jq -r '.[].firmware.fw_update_in_progress' <<< "$json")" + if [[ $in_prog == "true" ]]; then + sleep 1 + waited="$((waited + 1))" + continue + else + break + fi + if (( waited == max_wait )); then + echo "completion timeout for $mem" + err "$LINENO" + fi + done +} + +validate_json_state() +{ + json="$1" + state="$2" + + while read -r in_prog_state; do + if [[ $in_prog_state == $state ]]; then + continue + else + echo "expected fw_update_in_progress:$state" + err "$LINENO" + fi + done < <(jq -r '.[].firmware.fw_update_in_progress' <<< "$json") +} + +validate_fw_update_in_progress() +{ + validate_json_state "$1" "true" +} + +validate_fw_update_idle() +{ + validate_json_state "$1" "false" +} + +validate_staged_slot() +{ + json="$1" + slot="$2" + + while read -r staged_slot; do + if [[ $staged_slot == $slot ]]; then + continue + else + echo "expected staged_slot:$slot" + err "$LINENO" + fi + done < <(jq -r '.[].firmware.staged_slot' <<< "$json") +} + +check_sha() +{ + mem="$1" + file="$2" + csum_path="/sys/bus/platform/devices/cxl_mem.${mem#mem}/fw_buf_checksum" + + mem_csum="$(cat "$csum_path")" + file_csum="$(sha256sum "$file" | awk '{print $1}')" + + if [[ $mem_csum != $file_csum ]]; then + echo "checksum failure for mem$mem" + err "$LINENO" + fi +} + +test_blocking_update() +{ + file="$(mk_fw_file 8)" + mem="$(find_memdevs 1)" + json=$(do_update_fw -F "$file" --wait "$mem") + validate_fw_update_idle "$json" + # cxl_test's starting slot is '2', so staged should be 3 + validate_staged_slot "$json" 3 + check_sha "$mem" "$file" + rm "$file" +} + +test_nonblocking_update() +{ + file="$(mk_fw_file 16)" + mem="$(find_memdevs 1)" + json=$(do_update_fw -F "$file" "$mem") + validate_fw_update_in_progress "$json" + wait_complete "$mem" 15 + validate_fw_update_idle "$("$CXL" list -m "$mem" -F)" + check_sha "$mem" "$file" + rm "$file" +} + +test_multiple_memdev() +{ + num_mems=2 + + file="$(mk_fw_file 16)" + declare -a mems + mems=( $(find_memdevs "$num_mems") ) + json="$(do_update_fw -F "$file" "${mems[@]}")" + validate_fw_update_in_progress "$json" + # use the in-band wait this time + json="$(do_update_fw --wait "${mems[@]}")" + validate_fw_update_idle "$json" + for mem in ${mems[@]}; do + check_sha "$mem" "$file" + done + rm "$file" +} + +test_cancel() +{ + file="$(mk_fw_file 16)" + mem="$(find_memdevs 1)" + json=$(do_update_fw -F "$file" "$mem") + validate_fw_update_in_progress "$json" + do_update_fw --cancel "$mem" + # cancellation is asynchronous, and the result looks the same as idle + wait_complete "$mem" 15 + validate_fw_update_idle "$("$CXL" list -m "$mem" -F)" + # no need to check_sha + rm "$file" +} + +test_blocking_update +test_nonblocking_update +test_multiple_memdev +test_cancel + +check_dmesg "$LINENO" +modprobe -r cxl_test diff --git a/test/meson.build b/test/meson.build index a956885..0f4d3c4 100644 --- a/test/meson.build +++ b/test/meson.build @@ -155,6 +155,7 @@ cxl_sysfs = find_program('cxl-region-sysfs.sh') cxl_labels = find_program('cxl-labels.sh') cxl_create_region = find_program('cxl-create-region.sh') cxl_xor_region = find_program('cxl-xor-region.sh') +cxl_update_firmware = find_program('cxl-update-firmware.sh') tests = [ [ 'libndctl', libndctl, 'ndctl' ], @@ -198,6 +199,7 @@ if get_option('destructive').enabled() tests += [ [ 'firmware-update.sh', firmware_update, 'ndctl' ], + [ 'cxl-update-firmware.sh', cxl_update_firmware, 'cxl' ], [ 'pmem-ns', pmem_ns, 'ndctl' ], [ 'sub-section.sh', sub_section, 'dax' ], [ 'dax-dev', dax_dev, 'dax' ],