summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cxlflash
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/cxlflash')
-rw-r--r--drivers/scsi/cxlflash/ocxl_hw.c57
-rw-r--r--drivers/scsi/cxlflash/ocxl_hw.h2
2 files changed, 57 insertions, 2 deletions
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 <linux/idr.h>
#include <linux/module.h>
#include <linux/mount.h>
+#include <linux/poll.h>
#include <misc/ocxl.h>
@@ -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 */