]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.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)
committerStefan Bader <stefan.bader@canonical.com>
Mon, 1 Oct 2018 16:23:18 +0000 (18:23 +0200)
BugLink: https://bugs.launchpad.net/bugs/1794156
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>
(cherry picked from commit 1c09b663168bb5fd8562234976b76115f2aebe91)
Signed-off-by: dann frazier <dann.frazier@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.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 1385657ba1dcbe329bf8dcb3723776e3a5db481b..71c25b5ae3a18448b41440871d45f4e15a0427c2 100644 (file)
@@ -480,7 +480,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;
 
@@ -1758,7 +1758,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 f3e852adc9ad1e0e9e0622650f288e23061dd7e2..acc5382ba8fe21613e70fdc25a8b80b75af2ccfc 100644 (file)
@@ -930,23 +930,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 11bb01d88cb2b32b79b68ba562c9937c82263c74..daa2dd1848e97167b80bc709500150c03dc182ff 100644 (file)
@@ -1682,23 +1682,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 0031a199cf078944b7510dcc33caf6ed963a9fac..03c5f56ccca6048ba44d2df6310cd8d12c500b09 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);
 }