diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index 576a39e6b198..655377d17a70 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -452,6 +453,7 @@ static void *ocxlflash_dev_context_init(struct pci_dev *pdev, void *afu_cookie) } spin_lock_init(&ctx->slock); + init_waitqueue_head(&ctx->wq); ctx->pe = rc; ctx->master = false; @@ -892,10 +894,57 @@ err1: goto out; } +/** + * ctx_event_pending() - check for any event pending on the context + * @ctx: Context to be checked. + * + * Return: true if there is an event pending, false if none pending + */ +static inline bool ctx_event_pending(struct ocxlflash_context *ctx) +{ + if (ctx->pending_irq) + return true; + + return false; +} + +/** + * afu_poll() - poll the AFU for events on the context + * @file: File associated with the adapter context. + * @poll: Poll structure from the user. + * + * Return: poll mask + */ +static unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) +{ + struct ocxlflash_context *ctx = file->private_data; + struct device *dev = ctx->hw_afu->dev; + ulong lock_flags; + int mask = 0; + + poll_wait(file, &ctx->wq, poll); + + spin_lock_irqsave(&ctx->slock, lock_flags); + if (ctx_event_pending(ctx)) + mask |= POLLIN | POLLRDNORM; + else + mask |= POLLERR; + spin_unlock_irqrestore(&ctx->slock, lock_flags); + + dev_dbg(dev, "%s: Poll wait completed for pe %i mask %i\n", + __func__, ctx->pe, mask); + + return mask; +} + static const struct file_operations ocxl_afu_fops = { .owner = THIS_MODULE, + .poll = afu_poll, }; +#define PATCH_FOPS(NAME) \ + do { if (!fops->NAME) fops->NAME = ocxl_afu_fops.NAME; } while (0) + /** * ocxlflash_get_fd() - get file descriptor for an adapter context * @ctx_cookie: Adapter context. @@ -933,8 +982,10 @@ static struct file *ocxlflash_get_fd(void *ctx_cookie, } fdtmp = rc; - /* Use default ops if there is no fops */ - if (!fops) + /* Patch the file ops that are not defined */ + if (fops) { + PATCH_FOPS(poll); + } else /* Use default ops */ fops = (struct file_operations *)&ocxl_afu_fops; name = kasprintf(GFP_KERNEL, "ocxlflash:%d", ctx->pe); @@ -998,6 +1049,8 @@ static irqreturn_t ocxlflash_afu_irq(int irq, void *data) set_bit(i - 1, &ctx->irq_bitmap); ctx->pending_irq = true; spin_unlock(&ctx->slock); + + wake_up_all(&ctx->wq); out: return IRQ_HANDLED; } diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h index 2eb53901daf3..acd280135989 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.h +++ b/drivers/scsi/cxlflash/ocxl_hw.h @@ -56,6 +56,8 @@ struct ocxlflash_context { u64 psn_size; /* Process mapping size */ spinlock_t slock; /* Protects irq/fault/event updates */ + wait_queue_head_t wq; /* Wait queue for poll and interrupts */ + struct ocxlflash_irqs *irqs; /* Pointer to array of structures */ int num_irqs; /* Number of interrupts */ bool pending_irq; /* Pending interrupt on the context */