From: Vishal Verma <vishal.l.verma@intel.com>
To: linux-cxl@vger.kernel.org
Cc: nvdimm@lists.linux.dev,
Alison Schofield <alison.schofield@intel.com>,
Ira Weiny <ira.weiny@intel.com>,
Dave Jiang <dave.jiang@intel.com>,
Dan Williams <dan.j.williams@intel.com>,
Vishal Verma <vishal.l.verma@intel.com>
Subject: [PATCH ndctl 3/5] cxl/fw_loader: add APIs to get current state of the FW loader mechanism
Date: Fri, 21 Apr 2023 21:10:01 -0600 [thread overview]
Message-ID: <20230405-vv-fw_update-v1-3-722a7a5baea3@intel.com> (raw)
In-Reply-To: <20230405-vv-fw_update-v1-0-722a7a5baea3@intel.com>
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 <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
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;
--
2.40.0
next prev parent reply other threads:[~2023-04-22 3:12 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-22 3:09 [PATCH ndctl 0/5] cxl: firmware update support for libcxl and cxl-cli Vishal Verma
2023-04-22 3:09 ` [PATCH ndctl 1/5] cxl/memdev.c: allow filtering memdevs by bus Vishal Verma
2023-05-19 17:57 ` Dave Jiang
2023-04-22 3:10 ` [PATCH ndctl 2/5] cxl/list: print firmware info in memdev listings Vishal Verma
2023-05-19 18:21 ` Dave Jiang
2023-04-22 3:10 ` Vishal Verma [this message]
2023-05-19 18:49 ` [PATCH ndctl 3/5] cxl/fw_loader: add APIs to get current state of the FW loader mechanism Dave Jiang
2023-04-22 3:10 ` [PATCH ndctl 4/5] cxl: add an update-firmware command Vishal Verma
2023-04-24 23:14 ` Verma, Vishal L
2023-05-19 18:57 ` Dave Jiang
2023-04-22 3:10 ` [PATCH ndctl 5/5] test/cxl-update-firmware: add a unit test for firmware update Vishal Verma
2023-05-19 19:00 ` Dave Jiang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230405-vv-fw_update-v1-3-722a7a5baea3@intel.com \
--to=vishal.l.verma@intel.com \
--cc=alison.schofield@intel.com \
--cc=dan.j.williams@intel.com \
--cc=dave.jiang@intel.com \
--cc=ira.weiny@intel.com \
--cc=linux-cxl@vger.kernel.org \
--cc=nvdimm@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox