115 lines
4.1 KiB
Diff
115 lines
4.1 KiB
Diff
From 88439e5fcb32a4593b0e8cbfc7572a15793bcb3d Mon Sep 17 00:00:00 2001
|
|
From: Qi Liu <liuqi115@huawei.com>
|
|
Date: Tue, 15 Nov 2022 23:03:42 +0800
|
|
Subject: [PATCH 089/108] scsi: hisi_sas: Fix phyup timeout on FPGA
|
|
|
|
mainline inclusion
|
|
from mainline-v5.17-rc1
|
|
commit 37310bad7fa645b21653fd7f13cb6b376d80c919
|
|
category: bugfix
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EKNE
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=37310bad7fa645b21653fd7f13cb6b376d80c919
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
The OOB interrupt and phyup interrupt handlers may run out-of-order in high
|
|
CPU usage scenarios. Since the hisi_sas_phy.timer is added in
|
|
hisi_sas_phy_oob_ready() and disarmed in phy_up_v3_hw(), this out-of-order
|
|
execution will cause hisi_sas_phy.timer timeout to trigger.
|
|
|
|
To solve, protect hisi_sas_phy.timer and .attached with a lock, and ensure
|
|
that the timer won't be added after phyup handler completes.
|
|
|
|
Link: https://lore.kernel.org/r/1639579061-179473-8-git-send-email-john.garry@huawei.com
|
|
Signed-off-by: Qi Liu <liuqi115@huawei.com>
|
|
Signed-off-by: John Garry <john.garry@huawei.com>
|
|
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
|
Signed-off-by: xiabing <xiabing12@h-partners.com>
|
|
Reviewed-by: Xiang Chen <chenxiang66@hisilicon.com>
|
|
Reviewed-by: Jason Yan <yanaijie@huawei.com>
|
|
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
|
|
Signed-off-by: YunYi Yang <yangyunyi2@huawei.com>
|
|
---
|
|
drivers/scsi/hisi_sas/hisi_sas_main.c | 18 +++++++++++++-----
|
|
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 ++++++++--
|
|
2 files changed, 21 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
index 966308955831..48831be1b912 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
|
|
@@ -949,10 +949,14 @@ void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
|
|
{
|
|
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
|
|
struct device *dev = hisi_hba->dev;
|
|
+ unsigned long flags;
|
|
|
|
dev_dbg(dev, "phy%d OOB ready\n", phy_no);
|
|
- if (phy->phy_attached)
|
|
+ spin_lock_irqsave(&phy->lock, flags);
|
|
+ if (phy->phy_attached) {
|
|
+ spin_unlock_irqrestore(&phy->lock, flags);
|
|
return;
|
|
+ }
|
|
|
|
if (!timer_pending(&phy->timer)) {
|
|
if (phy->wait_phyup_cnt < HISI_SAS_WAIT_PHYUP_RETRIES) {
|
|
@@ -960,13 +964,17 @@ void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
|
|
phy->timer.expires = jiffies +
|
|
HISI_SAS_WAIT_PHYUP_TIMEOUT;
|
|
add_timer(&phy->timer);
|
|
- } else {
|
|
- dev_warn(dev, "phy%d failed to come up %d times, giving up\n",
|
|
- phy_no, phy->wait_phyup_cnt);
|
|
- phy->wait_phyup_cnt = 0;
|
|
+ spin_unlock_irqrestore(&phy->lock, flags);
|
|
+ return;
|
|
}
|
|
+
|
|
+ dev_warn(dev, "phy%d failed to come up %d times, giving up\n",
|
|
+ phy_no, phy->wait_phyup_cnt);
|
|
+ phy->wait_phyup_cnt = 0;
|
|
}
|
|
+ spin_unlock_irqrestore(&phy->lock, flags);
|
|
}
|
|
+
|
|
EXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready);
|
|
|
|
static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
|
|
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
index e917d6e9da10..adeddff88326 100644
|
|
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
|
|
@@ -1637,7 +1637,6 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
|
|
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
|
struct device *dev = hisi_hba->dev;
|
|
|
|
- del_timer(&phy->timer);
|
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
|
|
|
/* Port id store in 4 bits */
|
|
@@ -1717,11 +1716,18 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
|
|
}
|
|
|
|
phy->port_id = port_id;
|
|
- phy->phy_attached = 1;
|
|
+
|
|
/* Call pm_runtime_put_sync() with pairs in hisi_sas_phyup_pm_work() */
|
|
pm_runtime_get_noresume(dev);
|
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP_PM);
|
|
+
|
|
res = IRQ_HANDLED;
|
|
+
|
|
+ spin_lock(&phy->lock);
|
|
+ /* Delete timer and set phy_attached atomically */
|
|
+ del_timer(&phy->timer);
|
|
+ phy->phy_attached = 1;
|
|
+ spin_unlock(&phy->lock);
|
|
end:
|
|
if (phy->reset_completion)
|
|
complete(phy->reset_completion);
|
|
--
|
|
2.27.0
|
|
|