]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
scsi: hisi_sas: Add support for interrupt coalescing for v3 hw
authorXiang Chen <chenxiang66@hisilicon.com>
Fri, 9 Nov 2018 14:06:34 +0000 (22:06 +0800)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Mon, 14 Jan 2019 09:28:55 +0000 (09:28 +0000)
BugLink: https://bugs.launchpad.net/bugs/1810457
If INT_COAL_EN is enabled, configure time and count of interrupt
coalescing.  Then if CQ collects count of CQ entries in time, it will
report the interrupt. Or if CQ doesn't collect enough CQ entries in time,
it will report the interrupt at timeout.

As all the registers are not supported to be changed dynamically, we need
to config those register between disable and enable PHYs.

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 37359798ec44ae03fab383a9bef3b7c9df819063)
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: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 94a9e13c069cbc9277c555aa9338050049450203..535c61391250109b73e2cba7995c87237db9b527 100644 (file)
@@ -322,6 +322,8 @@ struct hisi_hba {
        unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)];
        struct work_struct rst_work;
        u32 phy_state;
+       u32 intr_coal_ticks;    /* Time of interrupt coalesce in us */
+       u32 intr_coal_count;    /* Interrupt count to coalesce */
 };
 
 /* Generic HW DMA host memory structures */
index 546eaf99ffc426ef39fb1593cfc2590e60dd2f8a..6ebb220767a3e33f612566d4ee0e286c04380174 100644 (file)
@@ -2105,9 +2105,109 @@ static ssize_t intr_conv_v3_hw_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(intr_conv_v3_hw);
 
+static void config_intr_coal_v3_hw(struct hisi_hba *hisi_hba)
+{
+       /* config those registers between enable and disable PHYs */
+       hisi_sas_stop_phys(hisi_hba);
+
+       if (hisi_hba->intr_coal_ticks == 0 ||
+           hisi_hba->intr_coal_count == 0) {
+               hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
+               hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1);
+               hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1);
+       } else {
+               hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x3);
+               hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME,
+                                hisi_hba->intr_coal_ticks);
+               hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT,
+                                hisi_hba->intr_coal_count);
+       }
+       phys_init_v3_hw(hisi_hba);
+}
+
+static ssize_t intr_coal_ticks_v3_hw_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n",
+                        hisi_hba->intr_coal_ticks);
+}
+
+static ssize_t intr_coal_ticks_v3_hw_store(struct device *dev,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+       u32 intr_coal_ticks;
+       int ret;
+
+       ret = kstrtou32(buf, 10, &intr_coal_ticks);
+       if (ret) {
+               dev_err(dev, "Input data of interrupt coalesce unmatch\n");
+               return -EINVAL;
+       }
+
+       if (intr_coal_ticks >= BIT(24)) {
+               dev_err(dev, "intr_coal_ticks must be less than 2^24!\n");
+               return -EINVAL;
+       }
+
+       hisi_hba->intr_coal_ticks = intr_coal_ticks;
+
+       config_intr_coal_v3_hw(hisi_hba);
+
+       return count;
+}
+static DEVICE_ATTR_RW(intr_coal_ticks_v3_hw);
+
+static ssize_t intr_coal_count_v3_hw_show(struct device *dev,
+                                         struct device_attribute
+                                         *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n",
+                        hisi_hba->intr_coal_count);
+}
+
+static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
+               struct device_attribute
+               *attr, const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+       u32 intr_coal_count;
+       int ret;
+
+       ret = kstrtou32(buf, 10, &intr_coal_count);
+       if (ret) {
+               dev_err(dev, "Input data of interrupt coalesce unmatch\n");
+               return -EINVAL;
+       }
+
+       if (intr_coal_count >= BIT(8)) {
+               dev_err(dev, "intr_coal_count must be less than 2^8!\n");
+               return -EINVAL;
+       }
+
+       hisi_hba->intr_coal_count = intr_coal_count;
+
+       config_intr_coal_v3_hw(hisi_hba);
+
+       return count;
+}
+static DEVICE_ATTR_RW(intr_coal_count_v3_hw);
+
 struct device_attribute *host_attrs_v3_hw[] = {
        &dev_attr_phy_event_threshold,
        &dev_attr_intr_conv_v3_hw,
+       &dev_attr_intr_coal_ticks_v3_hw,
+       &dev_attr_intr_coal_count_v3_hw,
        NULL
 };