From 3bb65a0c8cc8e8eaba87799ae86b7a177988065e Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Wed, 9 Jun 2021 18:25:57 +0530 Subject: [PATCH] msm: pci : Avoid deadlock with recovery and enemurate lock Avoid deadlock scenario when wake interrupt arrives at enumeration time and holds recovery lock and wake handler workqueue tries to acquire enumeration lock. In parallel client driver can call msm_pcie_pm_control for suspend where enumeration lock could be successfully acquired by msm_pcie_pm_control instead by wake handler and waiting for recovery lock which is currently acquired by wake handler (which is currently waiting for enumertion lock) which could leads to deadlock scenario. msm_pcie_enumerate wake handler pm_control | | (suspend thread) | | | | x acquired | x acquired | recovery lock | | enumerate lock | | | o waiting for | | enumerate lock | x released x acquired | enumerate lock | enumerate lock | o waiting for recovery lock we have fixed the order of locking in msm_pcie_pm_control to avoid deadlock scenario. Change-Id: Ifc72c643f7c0793cfa10a953723e953ce73a82b6 Signed-off-by: Vivek Pernamitta --- drivers/pci/controller/pci-msm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index e58be80b51b2..ce014787acbe 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -7898,6 +7898,7 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, break; } + mutex_lock(&pcie_dev->recovery_lock); mutex_lock(&pcie_dev->enumerate_lock); /* @@ -7928,12 +7929,12 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, "PCIe: RC%d: request to suspend the link is rejected\n", pcie_dev->rc_idx); mutex_unlock(&pcie_dev->enumerate_lock); + mutex_unlock(&pcie_dev->recovery_lock); break; } pcie_dev->user_suspend = true; - mutex_lock(&pcie_dev->recovery_lock); ret = msm_pcie_pm_suspend(dev, user, data, options); if (ret) { @@ -7949,9 +7950,9 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, } } - mutex_unlock(&pcie_dev->recovery_lock); - mutex_unlock(&pcie_dev->enumerate_lock); + + mutex_unlock(&pcie_dev->recovery_lock); break; case MSM_PCIE_RESUME: PCIE_DBG(pcie_dev, @@ -7964,6 +7965,8 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, break; } + mutex_lock(&pcie_dev->recovery_lock); + /* when link was suspended and link resume is requested */ mutex_lock(&pcie_dev->enumerate_lock); list_for_each_entry(dev_info_itr, &pcie_dev->susp_ep_list, @@ -7990,10 +7993,10 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, PCIE_ERR(pcie_dev, "PCIe: RC%d: requested to resume when link is already powered on.\n", pcie_dev->rc_idx); + mutex_unlock(&pcie_dev->recovery_lock); break; } - mutex_lock(&pcie_dev->recovery_lock); ret = msm_pcie_pm_resume(dev, user, data, options); if (ret) { PCIE_ERR(pcie_dev,