scsi: hisi_sas: Sync complete queue for poll queue
authorXiang Chen <chenxiang66@hisilicon.com>
Tue, 7 Mar 2023 06:09:14 +0000 (14:09 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 10 Mar 2023 02:50:02 +0000 (21:50 -0500)
Currently we sync irq to avoid freeing task before using task in I/O
completion. After adding io_uring support, we need to do something similar
for poll queues.  As the process of CQ entries on poll queue are protected
by spinlock cq->lock, we can use spin_lock() + spin_unlock() on cq->lock to
make sure that CQ entries are processed to completion and then the complete
queue is synced.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Link: https://lore.kernel.org/r/1678169355-76215-4-git-send-email-chenxiang66@hisilicon.com
Reviewed-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index a0eed81828dc431b077450669323cb0fa0b7bc37..3a5fc3658d3a35983689a4ae1851a33d51a24595 100644 (file)
@@ -660,12 +660,13 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
-extern void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba);
 extern void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no);
 extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
                                enum hisi_sas_phy_event event);
 extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba);
 extern u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max);
+extern void hisi_sas_sync_cqs(struct hisi_hba *hisi_hba);
+extern void hisi_sas_sync_poll_cqs(struct hisi_hba *hisi_hba);
 extern void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba);
 extern void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba);
 #endif
index 628cfbe4053bd959c9dea334fa03d34b459d30ec..325d6d6a21c3d071828e58fa615b7f86cfaae571 100644 (file)
@@ -683,6 +683,55 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
        return sas_dev;
 }
 
+static void hisi_sas_sync_poll_cq(struct hisi_sas_cq *cq)
+{
+       /* make sure CQ entries being processed are processed to completion */
+       spin_lock(&cq->poll_lock);
+       spin_unlock(&cq->poll_lock);
+}
+
+static bool hisi_sas_queue_is_poll(struct hisi_sas_cq *cq)
+{
+       struct hisi_hba *hisi_hba = cq->hisi_hba;
+
+       if (cq->id < hisi_hba->queue_count - hisi_hba->iopoll_q_cnt)
+               return false;
+       return true;
+}
+
+static void hisi_sas_sync_cq(struct hisi_sas_cq *cq)
+{
+       if (hisi_sas_queue_is_poll(cq))
+               hisi_sas_sync_poll_cq(cq);
+       else
+               synchronize_irq(cq->irq_no);
+}
+
+void hisi_sas_sync_poll_cqs(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+
+               if (hisi_sas_queue_is_poll(cq))
+                       hisi_sas_sync_poll_cq(cq);
+       }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sync_poll_cqs);
+
+void hisi_sas_sync_cqs(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+
+               hisi_sas_sync_cq(cq);
+       }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sync_cqs);
+
 static void hisi_sas_tmf_aborted(struct sas_task *task)
 {
        struct hisi_sas_slot *slot = task->lldd_task;
@@ -694,10 +743,10 @@ static void hisi_sas_tmf_aborted(struct sas_task *task)
                struct hisi_sas_cq *cq =
                           &hisi_hba->cq[slot->dlvry_queue];
                /*
-                * sync irq to avoid free'ing task
+                * sync irq or poll queue to avoid free'ing task
                 * before using task in IO completion
                 */
-               synchronize_irq(cq->irq_no);
+               hisi_sas_sync_cq(cq);
                slot->task = NULL;
        }
 }
@@ -1551,11 +1600,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
                if (slot) {
                        /*
-                        * sync irq to avoid free'ing task
+                        * sync irq or poll queue to avoid free'ing task
                         * before using task in IO completion
                         */
                        cq = &hisi_hba->cq[slot->dlvry_queue];
-                       synchronize_irq(cq->irq_no);
+                       hisi_sas_sync_cq(cq);
                }
                spin_unlock_irqrestore(&task->task_state_lock, flags);
                rc = TMF_RESP_FUNC_COMPLETE;
@@ -1622,10 +1671,10 @@ static int hisi_sas_abort_task(struct sas_task *task)
                if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
                                        task->lldd_task) {
                        /*
-                        * sync irq to avoid free'ing task
+                        * sync irq or poll queue to avoid free'ing task
                         * before using task in IO completion
                         */
-                       synchronize_irq(cq->irq_no);
+                       hisi_sas_sync_cq(cq);
                        slot->task = NULL;
                }
        }
@@ -1896,10 +1945,10 @@ static bool hisi_sas_internal_abort_timeout(struct sas_task *task,
                        struct hisi_sas_cq *cq =
                                &hisi_hba->cq[slot->dlvry_queue];
                        /*
-                        * sync irq to avoid free'ing task
+                        * sync irq or poll queue to avoid free'ing task
                         * before using task in IO completion
                         */
-                       synchronize_irq(cq->irq_no);
+                       hisi_sas_sync_cq(cq);
                        slot->task = NULL;
                }
 
@@ -2003,18 +2052,6 @@ void hisi_sas_phy_bcast(struct hisi_sas_phy *phy)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_phy_bcast);
 
-void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba)
-{
-       int i;
-
-       for (i = 0; i < hisi_hba->cq_nvecs; i++) {
-               struct hisi_sas_cq *cq = &hisi_hba->cq[i];
-
-               synchronize_irq(cq->irq_no);
-       }
-}
-EXPORT_SYMBOL_GPL(hisi_sas_sync_irqs);
-
 int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type)
 {
        struct hisi_hba *hisi_hba = shost_priv(shost);
index 24282bcf33d25e07c87da92bbba19832134663fb..1f6c02632c6a6354a04340cadfda188ea885ede5 100644 (file)
@@ -2657,6 +2657,7 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
        int rc;
 
        interrupt_disable_v3_hw(hisi_hba);
+       hisi_sas_sync_poll_cqs(hisi_hba);
        hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
 
        hisi_sas_stop_phys(hisi_hba);
@@ -3069,7 +3070,7 @@ static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
 
        wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000);
 
-       hisi_sas_sync_irqs(hisi_hba);
+       hisi_sas_sync_cqs(hisi_hba);
 }
 
 static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)