]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
scsi: hisi_sas: add memory barrier in task delivery function
authorXiaofei Tan <tanxiaofei@huawei.com>
Wed, 18 Jul 2018 14:14:32 +0000 (22:14 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 20 Jul 2018 01:57:40 +0000 (21:57 -0400)
In task start delivery function, we need to add a memory barrier to prevent
re-ordering of reading memory by hardware. Because the slot data is set in
task prepare function and it could be running in another CPU.

This patch adds an memory barrier after s->ready is read in the task start
delivery function, and uses WRITE_ONCE() in the places where s->ready is
set to ensure that the compiler does not re-order.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 432a38a118b1d0f7f43acce1bead5eeb73287e98..a4e2e6aa9a6b8c9ea1ecda64dfde666f6e3efb6b 100644 (file)
@@ -446,7 +446,7 @@ static int hisi_sas_task_prep(struct sas_task *task,
        spin_unlock_irqrestore(&task->task_state_lock, flags);
 
        ++(*pass);
-       slot->ready = 1;
+       WRITE_ONCE(slot->ready, 1);
 
        return 0;
 
@@ -1749,7 +1749,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
        task->task_state_flags |= SAS_TASK_AT_INITIATOR;
        spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-       slot->ready = 1;
+       WRITE_ONCE(slot->ready, 1);
        /* send abort command to the chip */
        spin_lock_irqsave(&dq->lock, flags);
        list_add_tail(&slot->entry, &sas_dev->list);
index 7dc68740eac922dfb778fde759bfeaee2df7318a..8f60f0e0459960616faf1849739632ad2e7c01b2 100644 (file)
@@ -903,23 +903,28 @@ get_free_slot_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
 static void start_delivery_v1_hw(struct hisi_sas_dq *dq)
 {
        struct hisi_hba *hisi_hba = dq->hisi_hba;
-       struct hisi_sas_slot *s, *s1;
+       struct hisi_sas_slot *s, *s1, *s2 = NULL;
        struct list_head *dq_list;
        int dlvry_queue = dq->id;
-       int wp, count = 0;
+       int wp;
 
        dq_list = &dq->list;
        list_for_each_entry_safe(s, s1, &dq->list, delivery) {
                if (!s->ready)
                        break;
-               count++;
-               wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+               s2 = s;
                list_del(&s->delivery);
        }
 
-       if (!count)
+       if (!s2)
                return;
 
+       /*
+        * Ensure that memories for slots built on other CPUs is observed.
+        */
+       smp_rmb();
+       wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+
        hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
 }
 
index 159576e560d790f1d2a1e6da7098e9107fdd2e6a..5a3d6a775427493a55e50dbea31b0f110beb15ab 100644 (file)
@@ -1665,23 +1665,28 @@ get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
 static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
 {
        struct hisi_hba *hisi_hba = dq->hisi_hba;
-       struct hisi_sas_slot *s, *s1;
+       struct hisi_sas_slot *s, *s1, *s2 = NULL;
        struct list_head *dq_list;
        int dlvry_queue = dq->id;
-       int wp, count = 0;
+       int wp;
 
        dq_list = &dq->list;
        list_for_each_entry_safe(s, s1, &dq->list, delivery) {
                if (!s->ready)
                        break;
-               count++;
-               wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+               s2 = s;
                list_del(&s->delivery);
        }
 
-       if (!count)
+       if (!s2)
                return;
 
+       /*
+        * Ensure that memories for slots built on other CPUs is observed.
+        */
+       smp_rmb();
+       wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+
        hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
 }
 
index 3d20fcf38fdfce34f8d3d5db1e0cc0fbfacffc55..70e22993ef058e65b66861cc33417e765b7247a4 100644 (file)
@@ -882,23 +882,28 @@ get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
 static void start_delivery_v3_hw(struct hisi_sas_dq *dq)
 {
        struct hisi_hba *hisi_hba = dq->hisi_hba;
-       struct hisi_sas_slot *s, *s1;
+       struct hisi_sas_slot *s, *s1, *s2 = NULL;
        struct list_head *dq_list;
        int dlvry_queue = dq->id;
-       int wp, count = 0;
+       int wp;
 
        dq_list = &dq->list;
        list_for_each_entry_safe(s, s1, &dq->list, delivery) {
                if (!s->ready)
                        break;
-               count++;
-               wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+               s2 = s;
                list_del(&s->delivery);
        }
 
-       if (!count)
+       if (!s2)
                return;
 
+       /*
+        * Ensure that memories for slots built on other CPUs is observed.
+        */
+       smp_rmb();
+       wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+
        hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
 }