diff options
Diffstat (limited to 'drivers/scsi/cxlflash')
-rw-r--r-- | drivers/scsi/cxlflash/common.h | 2 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.c | 42 |
2 files changed, 37 insertions, 7 deletions
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index d11dcc59ff46..9d56b8c797c4 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -134,6 +134,7 @@ struct afu_cmd { struct afu *parent; struct scsi_cmnd *scp; struct completion cevent; + struct list_head queue; u8 cmd_tmf:1; @@ -181,6 +182,7 @@ struct afu { struct sisl_ioarcb *hsq_start; struct sisl_ioarcb *hsq_end; struct sisl_ioarcb *hsq_curr; + spinlock_t hrrq_slock; u64 *hrrq_start; u64 *hrrq_end; u64 *hrrq_curr; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 30c09593c122..8c207ba8474b 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1157,10 +1157,13 @@ cxlflash_sync_err_irq_exit: /** * process_hrrq() - process the read-response queue * @afu: AFU associated with the host. + * @doneq: Queue of commands harvested from the RRQ. + * + * This routine must be called holding the disabled RRQ spin lock. * * Return: The number of entries processed. */ -static int process_hrrq(struct afu *afu) +static int process_hrrq(struct afu *afu, struct list_head *doneq) { struct afu_cmd *cmd; struct sisl_ioasa *ioasa; @@ -1189,7 +1192,7 @@ static int process_hrrq(struct afu *afu) cmd = container_of(ioarcb, struct afu_cmd, rcb); } - cmd_complete(cmd); + list_add_tail(&cmd->queue, doneq); /* Advance to next entry or wrap and flip the toggle bit */ if (hrrq_curr < hrrq_end) @@ -1210,17 +1213,43 @@ static int process_hrrq(struct afu *afu) } /** + * process_cmd_doneq() - process a queue of harvested RRQ commands + * @doneq: Queue of completed commands. + * + * Note that upon return the queue can no longer be trusted. + */ +static void process_cmd_doneq(struct list_head *doneq) +{ + struct afu_cmd *cmd, *tmp; + + WARN_ON(list_empty(doneq)); + + list_for_each_entry_safe(cmd, tmp, doneq, queue) + cmd_complete(cmd); +} + +/** * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) * @irq: Interrupt number. * @data: Private data provided at interrupt registration, the AFU. * - * Return: Always return IRQ_HANDLED. + * Return: IRQ_HANDLED or IRQ_NONE when no ready entries found. */ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; + unsigned long hrrq_flags; + LIST_HEAD(doneq); + int num_entries = 0; - process_hrrq(afu); + spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags); + num_entries = process_hrrq(afu, &doneq); + spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags); + + if (num_entries == 0) + return IRQ_NONE; + + process_cmd_doneq(&doneq); return IRQ_HANDLED; } @@ -1540,14 +1569,13 @@ static int start_afu(struct cxlflash_cfg *cfg) init_pcr(cfg); - /* After an AFU reset, RRQ entries are stale, clear them */ + /* Initialize RRQ */ memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry)); - - /* Initialize RRQ pointers */ afu->hrrq_start = &afu->rrq_entry[0]; afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; afu->hrrq_curr = afu->hrrq_start; afu->toggle = 1; + spin_lock_init(&afu->hrrq_slock); /* Initialize SQ */ if (afu_is_sq_cmd_mode(afu)) { |