326 lines
11 KiB
Diff
326 lines
11 KiB
Diff
From 26e11334126ba91dd21fc47aca10d58d5c936c09 Mon Sep 17 00:00:00 2001
|
|
From: Xiang Chen <chenxiang66@hisilicon.com>
|
|
Date: Mon, 20 Jan 2020 20:22:31 +0800
|
|
Subject: [PATCH 068/108] scsi: hisi_sas: use threaded irq to process CQ
|
|
interrupts
|
|
|
|
mainline inclusion
|
|
from mainline-v5.6-rc1
|
|
commit 81f338e9709db0b67d05bab02809d6a4e6694884
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EKNE
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=81f338e9709db0b67d05bab02809d6a4e6694884
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Currently IRQ_EFFECTIVE_AFF_MASK is enabled for ARM_GIC and ARM_GIC3, so it
|
|
only allows a single target CPU in the affinity mask to process interrupts
|
|
and also interrupt thread, and the performance of using threaded irq is
|
|
almost the same as tasklet. But if the config is not enabled, the interrupt
|
|
thread will be allowed all the CPUs in the affinity mask. At that situation
|
|
it improves the performance (about 20%).
|
|
|
|
Note: IRQ_EFFECTIVE_AFF_MASK is configured differently for different
|
|
architecture chip, and it seems to be better to make it be configured
|
|
easily.
|
|
|
|
Link: https://lore.kernel.org/r/1579522957-4393-2-git-send-email-john.garry@huawei.com
|
|
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>
|
|
Signed-off-by: YunYi Yang <yangyunyi2@huawei.com>
|
|
|
|
Conflicts:
|
|
drivers/scsi/hisi_sas/hisi_sas.h
|
|
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
---
|
|
drivers/scsi/hisi_sas/hisi_sas.h | 4 ++--
|
|
drivers/scsi/hisi_sas/hisi_sas_main.c | 22 +++++++++---------
|
|
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 26 ++++++++-------------
|
|
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 32 ++++++++++++++------------
|
|
4 files changed, 40 insertions(+), 44 deletions(-)
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
|
|
index 707ee782faa5..c9ff2e34d708 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas.h
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
|
|
@@ -202,9 +202,9 @@ struct hisi_sas_port {
|
|
struct hisi_sas_cq {
|
|
struct hisi_hba *hisi_hba;
|
|
const struct cpumask *pci_irq_mask;
|
|
- struct tasklet_struct tasklet;
|
|
int rd_point;
|
|
int id;
|
|
+ int irq_no;
|
|
};
|
|
|
|
struct hisi_sas_dq {
|
|
@@ -677,7 +677,7 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
|
|
extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
|
|
extern void hisi_sas_rst_work_handler(struct work_struct *work);
|
|
extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
|
|
-extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
|
|
+extern void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba);
|
|
extern void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no);
|
|
extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
|
|
enum hisi_sas_phy_event event);
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
index 4b58e2f3ca03..62fc39c27af8 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
@@ -1270,10 +1270,10 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
|
|
struct hisi_sas_cq *cq =
|
|
&hisi_hba->cq[slot->dlvry_queue];
|
|
/*
|
|
- * flush tasklet to avoid free'ing task
|
|
+ * sync irq to avoid free'ing task
|
|
* before using task in IO completion
|
|
*/
|
|
- tasklet_kill(&cq->tasklet);
|
|
+ synchronize_irq(cq->irq_no);
|
|
slot->task = NULL;
|
|
}
|
|
|
|
@@ -1677,11 +1677,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
|
|
|
if (slot) {
|
|
/*
|
|
- * flush tasklet to avoid free'ing task
|
|
+ * sync irq to avoid free'ing task
|
|
* before using task in IO completion
|
|
*/
|
|
cq = &hisi_hba->cq[slot->dlvry_queue];
|
|
- tasklet_kill(&cq->tasklet);
|
|
+ synchronize_irq(cq->irq_no);
|
|
}
|
|
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
|
rc = TMF_RESP_FUNC_COMPLETE;
|
|
@@ -1755,10 +1755,10 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
|
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
|
|
task->lldd_task) {
|
|
/*
|
|
- * flush tasklet to avoid free'ing task
|
|
+ * sync irq to avoid free'ing task
|
|
* before using task in IO completion
|
|
*/
|
|
- tasklet_kill(&cq->tasklet);
|
|
+ synchronize_irq(cq->irq_no);
|
|
slot->task = NULL;
|
|
}
|
|
}
|
|
@@ -2142,10 +2142,10 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|
struct hisi_sas_cq *cq =
|
|
&hisi_hba->cq[slot->dlvry_queue];
|
|
/*
|
|
- * flush tasklet to avoid free'ing task
|
|
+ * sync irq to avoid free'ing task
|
|
* before using task in IO completion
|
|
*/
|
|
- tasklet_kill(&cq->tasklet);
|
|
+ synchronize_irq(cq->irq_no);
|
|
slot->task = NULL;
|
|
}
|
|
dev_err(dev, "internal task abort: timeout and not done.\n");
|
|
@@ -2298,17 +2298,17 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
|
|
}
|
|
EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
|
|
|
|
-void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba)
|
|
+void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < hisi_hba->nvecs; i++) {
|
|
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
|
|
|
- tasklet_kill(&cq->tasklet);
|
|
+ synchronize_irq(cq->irq_no);
|
|
}
|
|
}
|
|
-EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets);
|
|
+EXPORT_SYMBOL_GPL(hisi_sas_sync_irqs);
|
|
|
|
int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type)
|
|
{
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
|
|
index 1d1ee655c9fb..55331ffa3be5 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
|
|
@@ -3128,9 +3128,9 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
-static void cq_tasklet_v2_hw(unsigned long val)
|
|
+static irqreturn_t cq_thread_v2_hw(int irq_no, void *p)
|
|
{
|
|
- struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
|
|
+ struct hisi_sas_cq *cq = p;
|
|
struct hisi_hba *hisi_hba = cq->hisi_hba;
|
|
struct hisi_sas_slot *slot;
|
|
struct hisi_sas_itct *itct;
|
|
@@ -3192,6 +3192,8 @@ static void cq_tasklet_v2_hw(unsigned long val)
|
|
/* update rd_point */
|
|
cq->rd_point = rd_point;
|
|
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
|
|
@@ -3202,9 +3204,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
|
|
|
|
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
|
|
|
|
- tasklet_schedule(&cq->tasklet);
|
|
-
|
|
- return IRQ_HANDLED;
|
|
+ return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
|
@@ -3371,18 +3371,18 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
|
|
|
|
for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) {
|
|
struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
|
|
- struct tasklet_struct *t = &cq->tasklet;
|
|
|
|
- irq = irq_map[queue_no + 96];
|
|
- rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
|
|
- DRV_NAME " cq", cq);
|
|
+ cq->irq_no = irq_map[queue_no + 96];
|
|
+ rc = devm_request_threaded_irq(dev, cq->irq_no,
|
|
+ cq_interrupt_v2_hw,
|
|
+ cq_thread_v2_hw, IRQF_ONESHOT,
|
|
+ DRV_NAME " cq", cq);
|
|
if (rc) {
|
|
dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
|
|
irq, rc);
|
|
rc = -ENOENT;
|
|
goto err_out;
|
|
}
|
|
- tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
|
|
}
|
|
|
|
hisi_hba->nvecs = hisi_hba->queue_count;
|
|
@@ -3444,7 +3444,6 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
|
|
|
|
interrupt_disable_v2_hw(hisi_hba);
|
|
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
|
- hisi_sas_kill_tasklets(hisi_hba);
|
|
|
|
hisi_sas_stop_phys(hisi_hba);
|
|
|
|
@@ -3618,11 +3617,6 @@ static int hisi_sas_v2_probe(struct platform_device *pdev)
|
|
|
|
static int hisi_sas_v2_remove(struct platform_device *pdev)
|
|
{
|
|
- struct sas_ha_struct *sha = platform_get_drvdata(pdev);
|
|
- struct hisi_hba *hisi_hba = sha->lldd_ha;
|
|
-
|
|
- hisi_sas_kill_tasklets(hisi_hba);
|
|
-
|
|
return hisi_sas_remove(pdev);
|
|
}
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
index 5d99587b48f5..5c04df84b6eb 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
@@ -2639,9 +2639,9 @@ static void hisi_sas_disk_err_handler(struct hisi_hba *hisi_hba,
|
|
hisi_sas_ata_device_link_abort(device);
|
|
}
|
|
|
|
-static void cq_tasklet_v3_hw(unsigned long val)
|
|
+static irqreturn_t cq_thread_v3_hw(int irq_no, void *p)
|
|
{
|
|
- struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
|
|
+ struct hisi_sas_cq *cq = p;
|
|
struct hisi_hba *hisi_hba = cq->hisi_hba;
|
|
struct hisi_sas_slot *slot;
|
|
struct hisi_sas_complete_v3_hdr *complete_queue;
|
|
@@ -2685,6 +2685,8 @@ static void cq_tasklet_v3_hw(unsigned long val)
|
|
hisi_sas_write32(hisi_hba,
|
|
COMPL_Q_0_RD_PTR + (NEXT_DQCQ_REG_OFF * queue),
|
|
rd_point);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
|
|
@@ -2695,9 +2697,7 @@ static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
|
|
|
|
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
|
|
|
|
- tasklet_schedule(&cq->tasklet);
|
|
-
|
|
- return IRQ_HANDLED;
|
|
+ return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
static void setup_reply_map_v3_hw(struct hisi_hba *hisi_hba, int nvecs)
|
|
@@ -2800,24 +2800,28 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
|
|
if (hisi_sas_intr_conv)
|
|
dev_info(dev, "Enable interrupt converge\n");
|
|
|
|
- /* Init tasklets for cq only */
|
|
for (i = 0; i < hisi_hba->nvecs; i++) {
|
|
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
|
- struct tasklet_struct *t = &cq->tasklet;
|
|
int nr = hisi_sas_intr_conv ? PCI_IRQ_CQ_BASE :
|
|
PCI_IRQ_CQ_BASE + i;
|
|
- unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : 0;
|
|
|
|
- rc = devm_request_irq(dev, pci_irq_vector(pdev, nr),
|
|
- cq_interrupt_v3_hw, irqflags,
|
|
- DRV_NAME " cq", cq);
|
|
+ unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED :
|
|
+ IRQF_ONESHOT;
|
|
+
|
|
+ cq->irq_no = pci_irq_vector(pdev, nr);
|
|
+
|
|
+ rc = devm_request_threaded_irq(dev, cq->irq_no,
|
|
+ cq_interrupt_v3_hw,
|
|
+ cq_thread_v3_hw,
|
|
+ irqflags,
|
|
+ DRV_NAME " cq", cq);
|
|
+
|
|
if (rc) {
|
|
dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
|
|
i, rc);
|
|
return -ENOENT;
|
|
}
|
|
|
|
- tasklet_init(t, cq_tasklet_v3_hw, (uintptr_t)cq);
|
|
}
|
|
|
|
return 0;
|
|
@@ -2924,7 +2928,6 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
|
|
|
|
interrupt_disable_v3_hw(hisi_hba);
|
|
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
|
- hisi_sas_kill_tasklets(hisi_hba);
|
|
|
|
hisi_sas_stop_phys(hisi_hba);
|
|
|
|
@@ -3343,7 +3346,7 @@ static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
|
|
/* delay:100ms, timeout:5s */
|
|
wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000);
|
|
|
|
- hisi_sas_kill_tasklets(hisi_hba);
|
|
+ hisi_sas_sync_irqs(hisi_hba);
|
|
}
|
|
|
|
static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)
|
|
@@ -4984,7 +4987,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
|
|
sas_remove_host(sha->core.shost);
|
|
|
|
hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
|
|
- hisi_sas_kill_tasklets(hisi_hba);
|
|
pci_release_regions(pdev);
|
|
pci_disable_device(pdev);
|
|
hisi_sas_free(hisi_hba);
|
|
--
|
|
2.27.0
|
|
|