Michal Suchanek c803fd
From bc65c1c7bfb34a6eeea99eb725b467ff64eda3d8 Mon Sep 17 00:00:00 2001
Michal Suchanek c803fd
From: Uma Krishnan <ukrishn@linux.vnet.ibm.com>
Michal Suchanek c803fd
Date: Mon, 26 Mar 2018 11:33:41 -0500
Michal Suchanek c803fd
Subject: [PATCH] scsi: cxlflash: Support AFU interrupt management
Michal Suchanek c803fd
Michal Suchanek c803fd
References: FATE#325192
Michal Suchanek e3b8e6
Patch-mainline: v4.18-rc1
Michal Suchanek c803fd
Git-commit: bc65c1c7bfb34a6eeea99eb725b467ff64eda3d8
Michal Suchanek c803fd
Michal Suchanek c803fd
Add support to allocate and free AFU interrupts using the OCXL provider
Michal Suchanek c803fd
services. The trigger page returned upon successful allocation will be mapped
Michal Suchanek c803fd
and exposed to the cxlflash core in a future commit.
Michal Suchanek c803fd
Michal Suchanek c803fd
Signed-off-by: Uma Krishnan <ukrishn@linux.vnet.ibm.com>
Michal Suchanek c803fd
Acked-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>
Michal Suchanek c803fd
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Michal Suchanek c803fd
Acked-by: Michal Suchanek <msuchanek@suse.de>
Michal Suchanek c803fd
---
Michal Suchanek c803fd
 drivers/scsi/cxlflash/ocxl_hw.c | 104 ++++++++++++++++++++++++++++++++++++++++
Michal Suchanek c803fd
 drivers/scsi/cxlflash/ocxl_hw.h |  10 ++++
Michal Suchanek c803fd
 2 files changed, 114 insertions(+)
Michal Suchanek c803fd
Michal Suchanek c803fd
diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c
Michal Suchanek c803fd
index 8d21f945016d..75351c3ca9bd 100644
Michal Suchanek c803fd
--- a/drivers/scsi/cxlflash/ocxl_hw.c
Michal Suchanek c803fd
+++ b/drivers/scsi/cxlflash/ocxl_hw.c
Michal Suchanek c803fd
@@ -385,6 +385,108 @@ static ssize_t ocxlflash_read_adapter_vpd(struct pci_dev *pdev, void *buf,
Michal Suchanek c803fd
 }
Michal Suchanek c803fd
 
Michal Suchanek c803fd
 /**
Michal Suchanek c803fd
+ * free_afu_irqs() - internal service to free interrupts
Michal Suchanek c803fd
+ * @ctx:	Adapter context.
Michal Suchanek c803fd
+ */
Michal Suchanek c803fd
+static void free_afu_irqs(struct ocxlflash_context *ctx)
Michal Suchanek c803fd
+{
Michal Suchanek c803fd
+	struct ocxl_hw_afu *afu = ctx->hw_afu;
Michal Suchanek c803fd
+	struct device *dev = afu->dev;
Michal Suchanek c803fd
+	int i;
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	if (!ctx->irqs) {
Michal Suchanek c803fd
+		dev_err(dev, "%s: Interrupts not allocated\n", __func__);
Michal Suchanek c803fd
+		return;
Michal Suchanek c803fd
+	}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	for (i = ctx->num_irqs; i >= 0; i--)
Michal Suchanek c803fd
+		ocxl_link_free_irq(afu->link_token, ctx->irqs[i].hwirq);
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	kfree(ctx->irqs);
Michal Suchanek c803fd
+	ctx->irqs = NULL;
Michal Suchanek c803fd
+}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+/**
Michal Suchanek c803fd
+ * alloc_afu_irqs() - internal service to allocate interrupts
Michal Suchanek c803fd
+ * @ctx:	Context associated with the request.
Michal Suchanek c803fd
+ * @num:	Number of interrupts requested.
Michal Suchanek c803fd
+ *
Michal Suchanek c803fd
+ * Return: 0 on success, -errno on failure
Michal Suchanek c803fd
+ */
Michal Suchanek c803fd
+static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num)
Michal Suchanek c803fd
+{
Michal Suchanek c803fd
+	struct ocxl_hw_afu *afu = ctx->hw_afu;
Michal Suchanek c803fd
+	struct device *dev = afu->dev;
Michal Suchanek c803fd
+	struct ocxlflash_irqs *irqs;
Michal Suchanek c803fd
+	u64 addr;
Michal Suchanek c803fd
+	int rc = 0;
Michal Suchanek c803fd
+	int hwirq;
Michal Suchanek c803fd
+	int i;
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	if (ctx->irqs) {
Michal Suchanek c803fd
+		dev_err(dev, "%s: Interrupts already allocated\n", __func__);
Michal Suchanek c803fd
+		rc = -EEXIST;
Michal Suchanek c803fd
+		goto out;
Michal Suchanek c803fd
+	}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	if (num > OCXL_MAX_IRQS) {
Michal Suchanek c803fd
+		dev_err(dev, "%s: Too many interrupts num=%d\n", __func__, num);
Michal Suchanek c803fd
+		rc = -EINVAL;
Michal Suchanek c803fd
+		goto out;
Michal Suchanek c803fd
+	}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	irqs = kcalloc(num, sizeof(*irqs), GFP_KERNEL);
Michal Suchanek c803fd
+	if (unlikely(!irqs)) {
Michal Suchanek c803fd
+		dev_err(dev, "%s: Context irqs allocation failed\n", __func__);
Michal Suchanek c803fd
+		rc = -ENOMEM;
Michal Suchanek c803fd
+		goto out;
Michal Suchanek c803fd
+	}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	for (i = 0; i < num; i++) {
Michal Suchanek c803fd
+		rc = ocxl_link_irq_alloc(afu->link_token, &hwirq, &addr);
Michal Suchanek c803fd
+		if (unlikely(rc)) {
Michal Suchanek c803fd
+			dev_err(dev, "%s: ocxl_link_irq_alloc failed rc=%d\n",
Michal Suchanek c803fd
+				__func__, rc);
Michal Suchanek c803fd
+			goto err;
Michal Suchanek c803fd
+		}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+		irqs[i].hwirq = hwirq;
Michal Suchanek c803fd
+		irqs[i].ptrig = addr;
Michal Suchanek c803fd
+	}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	ctx->irqs = irqs;
Michal Suchanek c803fd
+	ctx->num_irqs = num;
Michal Suchanek c803fd
+out:
Michal Suchanek c803fd
+	return rc;
Michal Suchanek c803fd
+err:
Michal Suchanek c803fd
+	for (i = i-1; i >= 0; i--)
Michal Suchanek c803fd
+		ocxl_link_free_irq(afu->link_token, irqs[i].hwirq);
Michal Suchanek c803fd
+	kfree(irqs);
Michal Suchanek c803fd
+	goto out;
Michal Suchanek c803fd
+}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+/**
Michal Suchanek c803fd
+ * ocxlflash_allocate_afu_irqs() - allocates the requested number of interrupts
Michal Suchanek c803fd
+ * @ctx_cookie:	Context associated with the request.
Michal Suchanek c803fd
+ * @num:	Number of interrupts requested.
Michal Suchanek c803fd
+ *
Michal Suchanek c803fd
+ * Return: 0 on success, -errno on failure
Michal Suchanek c803fd
+ */
Michal Suchanek c803fd
+static int ocxlflash_allocate_afu_irqs(void *ctx_cookie, int num)
Michal Suchanek c803fd
+{
Michal Suchanek c803fd
+	return alloc_afu_irqs(ctx_cookie, num);
Michal Suchanek c803fd
+}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+/**
Michal Suchanek c803fd
+ * ocxlflash_free_afu_irqs() - frees the interrupts of an adapter context
Michal Suchanek c803fd
+ * @ctx_cookie:	Adapter context.
Michal Suchanek c803fd
+ */
Michal Suchanek c803fd
+static void ocxlflash_free_afu_irqs(void *ctx_cookie)
Michal Suchanek c803fd
+{
Michal Suchanek c803fd
+	free_afu_irqs(ctx_cookie);
Michal Suchanek c803fd
+}
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+/**
Michal Suchanek c803fd
  * ocxlflash_unconfig_afu() - unconfigure the AFU
Michal Suchanek c803fd
  * @afu: AFU associated with the host.
Michal Suchanek c803fd
  */
Michal Suchanek c803fd
@@ -750,6 +852,8 @@ const struct cxlflash_backend_ops cxlflash_ocxl_ops = {
Michal Suchanek c803fd
 	.release_context	= ocxlflash_release_context,
Michal Suchanek c803fd
 	.perst_reloads_same_image = ocxlflash_perst_reloads_same_image,
Michal Suchanek c803fd
 	.read_adapter_vpd	= ocxlflash_read_adapter_vpd,
Michal Suchanek c803fd
+	.allocate_afu_irqs	= ocxlflash_allocate_afu_irqs,
Michal Suchanek c803fd
+	.free_afu_irqs		= ocxlflash_free_afu_irqs,
Michal Suchanek c803fd
 	.create_afu		= ocxlflash_create_afu,
Michal Suchanek c803fd
 	.destroy_afu		= ocxlflash_destroy_afu,
Michal Suchanek c803fd
 	.get_fd			= ocxlflash_get_fd,
Michal Suchanek c803fd
diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h
Michal Suchanek c803fd
index 09fa94c73501..85b3fad24263 100644
Michal Suchanek c803fd
--- a/drivers/scsi/cxlflash/ocxl_hw.h
Michal Suchanek c803fd
+++ b/drivers/scsi/cxlflash/ocxl_hw.h
Michal Suchanek c803fd
@@ -12,6 +12,13 @@
Michal Suchanek c803fd
  * 2 of the License, or (at your option) any later version.
Michal Suchanek c803fd
  */
Michal Suchanek c803fd
 
Michal Suchanek c803fd
+#define OCXL_MAX_IRQS	4	/* Max interrupts per process */
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+struct ocxlflash_irqs {
Michal Suchanek c803fd
+	int hwirq;
Michal Suchanek c803fd
+	u64 ptrig;
Michal Suchanek c803fd
+};
Michal Suchanek c803fd
+
Michal Suchanek c803fd
 /* OCXL hardware AFU associated with the host */
Michal Suchanek c803fd
 struct ocxl_hw_afu {
Michal Suchanek c803fd
 	struct ocxlflash_context *ocxl_ctx; /* Host context */
Michal Suchanek c803fd
@@ -45,4 +52,7 @@ struct ocxlflash_context {
Michal Suchanek c803fd
 
Michal Suchanek c803fd
 	phys_addr_t psn_phys;		/* Process mapping */
Michal Suchanek c803fd
 	u64 psn_size;			/* Process mapping size */
Michal Suchanek c803fd
+
Michal Suchanek c803fd
+	struct ocxlflash_irqs *irqs;	/* Pointer to array of structures */
Michal Suchanek c803fd
+	int num_irqs;			/* Number of interrupts */
Michal Suchanek c803fd
 };
Michal Suchanek c803fd
-- 
Michal Suchanek c803fd
2.13.6
Michal Suchanek c803fd