diff mbox series

[ndctl,3/5] cxl/fw_loader: add APIs to get current state of the FW loader mechanism

Message ID 20230405-vv-fw_update-v1-3-722a7a5baea3@intel.com
State Superseded
Headers show
Series cxl: firmware update support for libcxl and cxl-cli | expand

Commit Message

Verma, Vishal L April 22, 2023, 3:10 a.m. UTC
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(+)

Comments

Dave Jiang May 19, 2023, 6:49 p.m. UTC | #1
On 4/21/23 8:10 PM, Vishal Verma wrote:
> 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);

Just call free_fwl()?

DJ

> +	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;
>
diff mbox series

Patch

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;