154 lines
4.7 KiB
Diff
154 lines
4.7 KiB
Diff
From 20ca5e4f2c4a2c08340225f074c56f7be1c86f5b Mon Sep 17 00:00:00 2001
|
|
From: Xiang Chen <chenxiang66@hisilicon.com>
|
|
Date: Fri, 9 Nov 2018 22:06:34 +0800
|
|
Subject: [PATCH 12/31] scsi: hisi_sas: Add support for interrupt coalescing
|
|
for v3 hw
|
|
Origin: https://git.kernel.org/linus/37359798ec44ae03fab383a9bef3b7c9df819063
|
|
|
|
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>
|
|
---
|
|
drivers/scsi/hisi_sas/hisi_sas.h | 2 +
|
|
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 100 +++++++++++++++++++++++++
|
|
2 files changed, 102 insertions(+)
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
|
|
index 94a9e13c069c..535c61391250 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas.h
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
|
|
@@ -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 */
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
index b70190936f1b..7d7cb73e4bee 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
@@ -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
|
|
};
|
|
|
|
--
|
|
2.20.1
|
|
|