[PATCH 5.13 023/151] net: wwan: mhi_wwan_ctrl: Fix possible deadlock

From: Greg Kroah-Hartman
Date: Mon Aug 16 2021 - 09:21:54 EST


From: Loic Poulain <loic.poulain@xxxxxxxxxx>

commit 34737e1320db6d51f0d140d5c684b9eb32f0da76 upstream.

Lockdep detected possible interrupt unsafe locking scenario:

CPU0 CPU1
---- ----
lock(&mhiwwan->rx_lock);
local_irq_disable();
lock(&mhi_cntrl->pm_lock);
lock(&mhiwwan->rx_lock);
<Interrupt>
lock(&mhi_cntrl->pm_lock);

*** DEADLOCK ***

To prevent this we need to disable the soft-interrupts when taking
the rx_lock.

Cc: stable@xxxxxxxxxxxxxxx
Fixes: fa588eba632d ("net: Add Qcom WWAN control driver")
Reported-by: Thomas Perrot <thomas.perrot@xxxxxxxxxxx>
Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx>
Reviewed-by: Sergey Ryazanov <ryazanov.s.a@xxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/net/wwan/mhi_wwan_ctrl.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

--- a/drivers/net/wwan/mhi_wwan_ctrl.c
+++ b/drivers/net/wwan/mhi_wwan_ctrl.c
@@ -41,14 +41,14 @@ struct mhi_wwan_dev {
/* Increment RX budget and schedule RX refill if necessary */
static void mhi_wwan_rx_budget_inc(struct mhi_wwan_dev *mhiwwan)
{
- spin_lock(&mhiwwan->rx_lock);
+ spin_lock_bh(&mhiwwan->rx_lock);

mhiwwan->rx_budget++;

if (test_bit(MHI_WWAN_RX_REFILL, &mhiwwan->flags))
schedule_work(&mhiwwan->rx_refill);

- spin_unlock(&mhiwwan->rx_lock);
+ spin_unlock_bh(&mhiwwan->rx_lock);
}

/* Decrement RX budget if non-zero and return true on success */
@@ -56,7 +56,7 @@ static bool mhi_wwan_rx_budget_dec(struc
{
bool ret = false;

- spin_lock(&mhiwwan->rx_lock);
+ spin_lock_bh(&mhiwwan->rx_lock);

if (mhiwwan->rx_budget) {
mhiwwan->rx_budget--;
@@ -64,7 +64,7 @@ static bool mhi_wwan_rx_budget_dec(struc
ret = true;
}

- spin_unlock(&mhiwwan->rx_lock);
+ spin_unlock_bh(&mhiwwan->rx_lock);

return ret;
}
@@ -130,9 +130,9 @@ static void mhi_wwan_ctrl_stop(struct ww
{
struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port);

- spin_lock(&mhiwwan->rx_lock);
+ spin_lock_bh(&mhiwwan->rx_lock);
clear_bit(MHI_WWAN_RX_REFILL, &mhiwwan->flags);
- spin_unlock(&mhiwwan->rx_lock);
+ spin_unlock_bh(&mhiwwan->rx_lock);

cancel_work_sync(&mhiwwan->rx_refill);