From patchwork Sat Apr 22 03:09:59 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: 13220887 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF6ACC77B61 for ; Sat, 22 Apr 2023 03:11:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229938AbjDVDLk (ORCPT ); Fri, 21 Apr 2023 23:11:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229540AbjDVDLJ (ORCPT ); Fri, 21 Apr 2023 23:11:09 -0400 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6524135BD for ; Fri, 21 Apr 2023 20:10:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682133031; x=1713669031; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=clo6OSob1Maw48Q8f5r4bj+OpAvWu1wDKgUzbfgm/a0=; b=fN848kb2TrP3l8JIgMBWN2kzOQVbKei4hKmlPRtQXPEURKrzA16ZXtdQ Nmz1b8AXjnbX8ttaHTbIkwg2zyN+N37hYd0yunbohEhfpm6R5g0Jo9Lqp /zt/kyK+Hl7lp3tSaDuMhiJDDyS2TjmH8/GeNxWA+h265eGaonyVjcQta T0EI7DDyFMbVttf+YA3vd62NvU1xOcRyewJrHwKOQLdwmwfVwvftiJ2nX +wBoTefNlxr/eE1AayTFriDKvHd5/0nEs7smntp+9ImSGz8RtFk2SHkrX KRTC5br1Kw73ExHbut5/aatMYfpqAeiw4QvbpKMepCKpfinAgkwHVk8rS Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="343609097" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="343609097" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="757092354" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="757092354" Received: from jwostman-mobl2.amr.corp.intel.com (HELO [192.168.1.200]) ([10.212.111.101]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:03 -0700 From: Vishal Verma Date: Fri, 21 Apr 2023 21:09:59 -0600 Subject: [PATCH ndctl 1/5] cxl/memdev.c: allow filtering memdevs by bus MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v1-1-722a7a5baea3@intel.com> References: <20230405-vv-fw_update-v1-0-722a7a5baea3@intel.com> In-Reply-To: <20230405-vv-fw_update-v1-0-722a7a5baea3@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-2eb1a X-Developer-Signature: v=1; a=openpgp-sha256; l=6014; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=clo6OSob1Maw48Q8f5r4bj+OpAvWu1wDKgUzbfgm/a0=; b=owGbwMvMwCXGf25diOft7jLG02pJDCnOAVz7StNqf6j9XFTzbD/n7L7nFkvdjyhMUAu1W7JyZ vqW5QxlHaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZjI+2hGhquld5MWd/6f/Ubr yi/ZhY/n6z3wFz30yMWWe+aceQprhEsZGSb/8D6xN5FT63+Jwu3mdRNPPTztsUSq/tSlJVHlJun PL3ACAA== X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org 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 Signed-off-by: Vishal Verma Reviewed-by: Dave Jiang --- 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 Sat Apr 22 03:10:00 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: 13220889 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE05FC7618E for ; Sat, 22 Apr 2023 03:12:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229572AbjDVDMC (ORCPT ); Fri, 21 Apr 2023 23:12:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229635AbjDVDL3 (ORCPT ); Fri, 21 Apr 2023 23:11:29 -0400 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE2CD30EB for ; Fri, 21 Apr 2023 20:11:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682133062; x=1713669062; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=vHqERkez6Tg5usfHgvgIchuLxIFTEu7KTMXlaAxFW+U=; b=DfSrdELjE7HlgT2x2WtvyQlpkFFJoZcQvCoY+vXO5epGnspkbbfBjzou XJtrrBVDxWGFjEPuKR32igwb47XmTNxuL+YWh42b1FpwHOWA7YfTCfhYn EsnRT/weTdvk2mbUHAhJ0rf/+SPMQJP9lkzzy41n5Rogf+FfyHGKJt0/i jdw7dxklJxQYHz2Gs7Tq6yPeYPSqzV9HfCFP/qblXdlATgNc0BgEPhZlJ Gr95/CzaC3FPEC+qLuPwBsESSvSqPDwhChgWZftdkigj8Gad3/2nn332U GGAs44pGuiyFQM+p50yqRfyFAFjH1l+eyTOanzzrQk5Jn1MlJFlHQtty9 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="343609099" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="343609099" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="757092365" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="757092365" Received: from jwostman-mobl2.amr.corp.intel.com (HELO [192.168.1.200]) ([10.212.111.101]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:04 -0700 From: Vishal Verma Date: Fri, 21 Apr 2023 21:10:00 -0600 Subject: [PATCH ndctl 2/5] cxl/list: print firmware info in memdev listings MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v1-2-722a7a5baea3@intel.com> References: <20230405-vv-fw_update-v1-0-722a7a5baea3@intel.com> In-Reply-To: <20230405-vv-fw_update-v1-0-722a7a5baea3@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-2eb1a X-Developer-Signature: v=1; a=openpgp-sha256; l=9629; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=vHqERkez6Tg5usfHgvgIchuLxIFTEu7KTMXlaAxFW+U=; b=owGbwMvMwCXGf25diOft7jLG02pJDCnOAdxfL+X07ptgeJlx1lvPY9dWC7kYPKxZto5F17pU0 zb0zd11HaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZjIMWdGhoubZvmeEMrMu3n4 9aavfROc2fepVOtIXOM73zP1wWon0yiGv/LHnDTEOZZ9UDrxtPpUrOgVyakb66Y9mHbLf9mrrzH 9X3gB X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org 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 Signed-off-by: Vishal Verma Reviewed-by: Dave Jiang --- 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..75490fd 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[0]; + break; + case 2: + fw_ver = &c->slot_2_revision[0]; + break; + case 3: + fw_ver = &c->slot_3_revision[0]; + break; + case 4: + fw_ver = &c->slot_4_revision[0]; + 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 Sat Apr 22 03:10:01 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: 13220888 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 75CCDC77B61 for ; Sat, 22 Apr 2023 03:12:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229565AbjDVDMB (ORCPT ); Fri, 21 Apr 2023 23:12:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33768 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229923AbjDVDL2 (ORCPT ); Fri, 21 Apr 2023 23:11:28 -0400 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DDB4F358E for ; Fri, 21 Apr 2023 20:11:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682133062; x=1713669062; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=zNG8XgHeVoCgrLpsepTOZ1HTcQzK8ar5KP4hS+0libI=; b=CRsw7p232haMRV3wF5fBGPvdbn0NzFpjhaChKF43vf2qs7JLAxssTcmw pe0h98A2uE3+ZZFhjDbVKXVuMZno9YkSnfoOgA4rk0NeQivDwVl1/4lzc /+KpvkyapMoN7ITEdGpiEcq2X6VGRtei1dK5PEvnmwTTuNKHP9pwH1lnU +2nc7G6yoJ9pe6sp7Eqp7HnWIFveIiZt2vPEaaf+0drd3HaF4sOM4CTHo fvSeaKDyqEOqnhFo+fPwRHJp0l3Re8SHLUx7l4oWVxpncnSO+Y7EviTU0 RJbEUdm7SmWzlfymr2ZLIRWoTui0t/KTV+hXs+i6QmH7jDp0c1CawStja A==; X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="343609102" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="343609102" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:04 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="757092376" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="757092376" Received: from jwostman-mobl2.amr.corp.intel.com (HELO [192.168.1.200]) ([10.212.111.101]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:04 -0700 From: Vishal Verma Date: Fri, 21 Apr 2023 21:10:01 -0600 Subject: [PATCH ndctl 3/5] cxl/fw_loader: add APIs to get current state of the FW loader mechanism MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v1-3-722a7a5baea3@intel.com> References: <20230405-vv-fw_update-v1-0-722a7a5baea3@intel.com> In-Reply-To: <20230405-vv-fw_update-v1-0-722a7a5baea3@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-2eb1a X-Developer-Signature: v=1; a=openpgp-sha256; l=8054; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=zNG8XgHeVoCgrLpsepTOZ1HTcQzK8ar5KP4hS+0libI=; b=owGbwMvMwCXGf25diOft7jLG02pJDCnOAdxluZffhdncuh2zQ75obkyxBvPBJW/vMqeuf+N6T tE5gmt6RykLgxgXg6yYIsvfPR8Zj8ltz+cJTHCEmcPKBDKEgYtTACbyexsjw7XdYqVPmxPSJhqf 3jLj0j+1v77XNvpWz3QMfVB0aulrbkdGhh8SF9c5pF7g+H1i+hyeWrWZh/bLfzkhOZfxS5XU7K2 be9gA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org 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 | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cxl/libcxl.h | 27 +++++++++++++++ cxl/json.c | 13 +++++++ cxl/lib/libcxl.sym | 2 ++ 5 files changed, 152 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 75490fd..86873d7 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,45 @@ 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->loading); + free(fwl->data); + free(fwl->remaining); + free(fwl->cancel); + free(fwl->status); + free(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 +1315,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 +1428,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 Sat Apr 22 03:10:02 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: 13220890 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C45D1C77B76 for ; Sat, 22 Apr 2023 03:12:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229596AbjDVDMD (ORCPT ); Fri, 21 Apr 2023 23:12:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33562 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229612AbjDVDLa (ORCPT ); Fri, 21 Apr 2023 23:11:30 -0400 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4191235B5 for ; Fri, 21 Apr 2023 20:11:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682133067; x=1713669067; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=qU6PDj9/mkuXW1+Egl0eDRlJx1/7xBz0S5uRzLKQ22U=; b=DoebFhIVE6LnMSLrA8bPmvNm1RPAELaJqHdBzIl+rVhCfE2AvzNk1VkL MWs2+TTcr4xtnLXBjg7Y3KYwIYevbjyqONuxGVEO126bLS+TatNO9KPJp A9kVfI57koP+XW4mAAybCZP28jCILMhu5w59RG2ycW0G3Asfz1M0Pf0YN IHTqEZnk5JIkdTlcyRZp4LdlRYHwvkA/uMsE947GFryw8j4wdz2V03DIG lwfsZ97q+MQbSSg0DWRDXF5JvSHaSgAf5Yy03XK8hPykdvG+baeg3XRnz GNj3JHsTF7Z46d6zZvqIgEap1gvquhKfoWg1sYASGhf7oLtR6qCF59lZx Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="343609103" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="343609103" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:05 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="757092392" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="757092392" Received: from jwostman-mobl2.amr.corp.intel.com (HELO [192.168.1.200]) ([10.212.111.101]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:04 -0700 From: Vishal Verma Date: Fri, 21 Apr 2023 21:10:02 -0600 Subject: [PATCH ndctl 4/5] cxl: add an update-firmware command MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v1-4-722a7a5baea3@intel.com> References: <20230405-vv-fw_update-v1-0-722a7a5baea3@intel.com> In-Reply-To: <20230405-vv-fw_update-v1-0-722a7a5baea3@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-2eb1a X-Developer-Signature: v=1; a=openpgp-sha256; l=10820; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=qU6PDj9/mkuXW1+Egl0eDRlJx1/7xBz0S5uRzLKQ22U=; b=owGbwMvMwCXGf25diOft7jLG02pJDCnOAdyHXi8zjT3+pHdlv0Yta+IPyRlpv+cIsz3r5fhx/ 8UVxqTPHaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZiIeRDDf6cX3eZHTt02WtNT m/p0S2d7Vopa/EzHScxhL2PUzepX6zEy/E2/Mj3o7PUmZl752En9q03sLcIuR/N8lr7y7GHggXQ 9ZgA= X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org 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. Signed-off-by: Vishal Verma Reviewed-by: Dave Jiang --- 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 + 8 files changed, 198 insertions(+), 1 deletion(-) 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 86873d7..8084857 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1473,6 +1474,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 Sat Apr 22 03:10: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: 13220891 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3B6CC77B61 for ; Sat, 22 Apr 2023 03:12:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229612AbjDVDMH (ORCPT ); Fri, 21 Apr 2023 23:12:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229926AbjDVDLd (ORCPT ); Fri, 21 Apr 2023 23:11:33 -0400 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28CB930CB for ; Fri, 21 Apr 2023 20:11:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682133088; x=1713669088; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=a43/Y1KLgts2XRVilsrTojz96R4JG5ikNcl92jBCG7E=; b=S3OU9oirIwPcip8yU9BkwaVeMGujhWtKVwbNV4RUhhVmE8KDT8+4OI0w 1QipbEKgMYBDCbkWwHpWKN5Vi5huMQ6yGsOh4RD296ag+iQRO/Mz8ohi7 /UUVRtcl2IeofBEdnROlPB5qHukBxB3y1hfOWh7ElYGLUSSwJJNKxLGW+ mGbgna77pOEfgUeijK4Ly8LsLyM1C+DEPNVaB5Qhu7SHbgq60mfP+HmuD UcOGS7ardomdvoKLIOw0m1P8uG37J94l223RVNkfGYUXcZuPcfBXREGAA +IjECnLlRQ/GxgURzcg1BwR44QNCQK7cPE2JkQWm1buczABr5lXGETLtW g==; X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="343609105" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="343609105" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:05 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10687"; a="757092403" X-IronPort-AV: E=Sophos;i="5.99,216,1677571200"; d="scan'208";a="757092403" Received: from jwostman-mobl2.amr.corp.intel.com (HELO [192.168.1.200]) ([10.212.111.101]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 20:10:05 -0700 From: Vishal Verma Date: Fri, 21 Apr 2023 21:10:03 -0600 Subject: [PATCH ndctl 5/5] test/cxl-update-firmware: add a unit test for firmware update MIME-Version: 1.0 Message-Id: <20230405-vv-fw_update-v1-5-722a7a5baea3@intel.com> References: <20230405-vv-fw_update-v1-0-722a7a5baea3@intel.com> In-Reply-To: <20230405-vv-fw_update-v1-0-722a7a5baea3@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-2eb1a X-Developer-Signature: v=1; a=openpgp-sha256; l=5565; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=a43/Y1KLgts2XRVilsrTojz96R4JG5ikNcl92jBCG7E=; b=owGbwMvMwCXGf25diOft7jLG02pJDCnOAdx/XKN/7fgq0+2WLbz3jovVlVVJh/ZV/T1whdFa4 E4u+9HwjlIWBjEuBlkxRZa/ez4yHpPbns8TmOAIM4eVCWQIAxenAEwkeScjw/xV749nLL88+eHV +s2fpwZeK738T+OfoJuXn+Mio4NzyhQYGbZdb280DKzrTzVZcO3I2trXk6I/fg9fsdhMYIGckXJ xExsA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org 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 Signed-off-by: Vishal Verma Reviewed-by: Dave Jiang --- 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' ],