Add support to allocate and free AFU interrupts using the OCXL provider services. The trigger page returned upon successful allocation will be mapped and exposed to the cxlflash core in a future commit.
Signed-off-by: Uma Krishnan <ukri...@linux.vnet.ibm.com> Acked-by: Matthew R. Ochs <mro...@linux.vnet.ibm.com> --- drivers/scsi/cxlflash/ocxl_hw.c | 104 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/cxlflash/ocxl_hw.h | 10 ++++ 2 files changed, 114 insertions(+) diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index f18d82d..e04dce8 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -385,6 +385,108 @@ static ssize_t ocxlflash_read_adapter_vpd(struct pci_dev *pdev, void *buf, } /** + * free_afu_irqs() - internal service to free interrupts + * @ctx: Adapter context. + */ +static void free_afu_irqs(struct ocxlflash_context *ctx) +{ + struct ocxl_hw_afu *afu = ctx->hw_afu; + struct device *dev = afu->dev; + int i; + + if (!ctx->irqs) { + dev_err(dev, "%s: Interrupts not allocated\n", __func__); + return; + } + + for (i = ctx->num_irqs; i >= 0; i--) + ocxl_link_free_irq(afu->link_token, ctx->irqs[i].hwirq); + + kfree(ctx->irqs); + ctx->irqs = NULL; +} + +/** + * alloc_afu_irqs() - internal service to allocate interrupts + * @ctx: Context associated with the request. + * @num: Number of interrupts requested. + * + * Return: 0 on success, -errno on failure + */ +static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num) +{ + struct ocxl_hw_afu *afu = ctx->hw_afu; + struct device *dev = afu->dev; + struct ocxlflash_irqs *irqs; + u64 addr; + int rc = 0; + int hwirq; + int i; + + if (ctx->irqs) { + dev_err(dev, "%s: Interrupts already allocated\n", __func__); + rc = -EEXIST; + goto out; + } + + if (num > OCXL_MAX_IRQS) { + dev_err(dev, "%s: Too many interrupts num=%d\n", __func__, num); + rc = -EINVAL; + goto out; + } + + irqs = kcalloc(num, sizeof(*irqs), GFP_KERNEL); + if (unlikely(!irqs)) { + dev_err(dev, "%s: Context irqs allocation failed\n", __func__); + rc = -ENOMEM; + goto out; + } + + for (i = 0; i < num; i++) { + rc = ocxl_link_irq_alloc(afu->link_token, &hwirq, &addr); + if (unlikely(rc)) { + dev_err(dev, "%s: ocxl_link_irq_alloc failed rc=%d\n", + __func__, rc); + goto err; + } + + irqs[i].hwirq = hwirq; + irqs[i].ptrig = addr; + } + + ctx->irqs = irqs; + ctx->num_irqs = num; +out: + return rc; +err: + for (i = i-1; i >= 0; i--) + ocxl_link_free_irq(afu->link_token, irqs[i].hwirq); + kfree(irqs); + goto out; +} + +/** + * ocxlflash_allocate_afu_irqs() - allocates the requested number of interrupts + * @ctx_cookie: Context associated with the request. + * @num: Number of interrupts requested. + * + * Return: 0 on success, -errno on failure + */ +static int ocxlflash_allocate_afu_irqs(void *ctx_cookie, int num) +{ + return alloc_afu_irqs(ctx_cookie, num); +} + +/** + * ocxlflash_free_afu_irqs() - frees the interrupts of an adapter context + * @ctx_cookie: Adapter context. + */ +static void ocxlflash_free_afu_irqs(void *ctx_cookie) +{ + free_afu_irqs(ctx_cookie); +} + +/** * ocxlflash_unconfig_afu() - unconfigure the AFU * @afu: AFU associated with the host. */ @@ -742,6 +844,8 @@ const struct cxlflash_backend_ops cxlflash_ocxl_ops = { .release_context = ocxlflash_release_context, .perst_reloads_same_image = ocxlflash_perst_reloads_same_image, .read_adapter_vpd = ocxlflash_read_adapter_vpd, + .allocate_afu_irqs = ocxlflash_allocate_afu_irqs, + .free_afu_irqs = ocxlflash_free_afu_irqs, .create_afu = ocxlflash_create_afu, .destroy_afu = ocxlflash_destroy_afu, .get_fd = ocxlflash_get_fd, diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h index 4d43650..500de6b 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.h +++ b/drivers/scsi/cxlflash/ocxl_hw.h @@ -12,6 +12,13 @@ * 2 of the License, or (at your option) any later version. */ +#define OCXL_MAX_IRQS 4 /* Max interrupts per process */ + +struct ocxlflash_irqs { + int hwirq; + u64 ptrig; +}; + /* OCXL hardware AFU associated with the host */ struct ocxl_hw_afu { struct ocxlflash_context *ocxl_ctx; /* Host context */ @@ -44,4 +51,7 @@ struct ocxlflash_context { phys_addr_t psn_phys; /* Process mapping */ u64 psn_size; /* Process mapping size */ + + struct ocxlflash_irqs *irqs; /* Pointer to array of structures */ + int num_irqs; /* Number of interrupts */ }; -- 2.1.0