]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
scsi: hisi_sas: service interrupt ITCT_CLR interrupt in v2 hw
authorXiang Chen <chenxiang66@hisilicon.com>
Thu, 10 Aug 2017 16:09:33 +0000 (00:09 +0800)
committerKhalid Elmously <khalid.elmously@canonical.com>
Fri, 16 Feb 2018 17:42:11 +0000 (12:42 -0500)
BugLink: https://bugs.launchpad.net/bugs/1739807
This patch is a fix related to freeing a device in v2 hw driver.

Before, we polled to ITCT CLR interrupt to check if a device is free.

This was error prone, as if the interrupt doesn't occur in 10us, we miss
processing it.

To avoid this situation, service this interrupt and sync the event with
a completion.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
(cherry picked from commit 640acc9a9693e729b7936fb4801f2dd59041a141)
Signed-off-by: dann frazier <dann.frazier@canonical.com>
Acked-by: Paolo Pisati <paolo.pisati@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

index ef2238c6e4dae9cd91b2b6e2b2a3835f115978af..3070a42eca0b9fc56acadb983cad8d65227b1739 100644 (file)
@@ -133,6 +133,7 @@ struct hisi_sas_dq {
 struct hisi_sas_device {
        struct hisi_hba         *hisi_hba;
        struct domain_device    *sas_device;
+       struct completion *completion;
        struct hisi_sas_dq      *dq;
        struct list_head        list;
        u64 attached_phy;
index ff2f90d752983102794ca323a338abbf8002c9d3..4c6b1a6fa6757146e392c10af5028d1a3f641211 100644 (file)
@@ -808,12 +808,14 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 static void free_device_v2_hw(struct hisi_hba *hisi_hba,
                              struct hisi_sas_device *sas_dev)
 {
+       DECLARE_COMPLETION_ONSTACK(completion);
        u64 dev_id = sas_dev->device_id;
-       struct device *dev = hisi_hba->dev;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
        u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
        int i;
 
+       sas_dev->completion = &completion;
+
        /* SoC bug workaround */
        if (dev_is_sata(sas_dev->sas_device))
                clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
@@ -823,28 +825,12 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
                hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
                                 ENT_INT_SRC3_ITC_INT_MSK);
 
-       /* clear the itct int*/
        for (i = 0; i < 2; i++) {
-               /* clear the itct table*/
-               reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
-               reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
+               reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
                hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
+               wait_for_completion(sas_dev->completion);
 
-               udelay(10);
-               reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
-               if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
-                       dev_dbg(dev, "got clear ITCT done interrupt\n");
-
-                       /* invalid the itct state*/
-                       memset(itct, 0, sizeof(struct hisi_sas_itct));
-                       hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
-                                        ENT_INT_SRC3_ITC_INT_MSK);
-
-                       /* clear the itct */
-                       hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
-                       dev_dbg(dev, "clear ITCT ok\n");
-                       break;
-               }
+               memset(itct, 0, sizeof(struct hisi_sas_itct));
        }
 }
 
@@ -1025,7 +1011,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
        hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
        hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0x7efefefe);
        hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0x7efefefe);
-       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffffffe);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffe20fe);
        hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfff00c30);
        for (i = 0; i < hisi_hba->queue_count; i++)
                hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
@@ -3082,8 +3068,20 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
                              irq_value);
                        queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                }
+
+               if (irq_value & BIT(ENT_INT_SRC3_ITC_INT_OFF)) {
+                       u32 reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
+                       u32 dev_id = reg_val & ITCT_DEV_MSK;
+                       struct hisi_sas_device *sas_dev =
+                                       &hisi_hba->devices[dev_id];
+
+                       hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
+                       dev_dbg(dev, "clear ITCT ok\n");
+                       complete(sas_dev->completion);
+               }
        }
 
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC3, irq_value);
        hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk);
 
        return IRQ_HANDLED;