From: Heikki Krogerus <[email protected]>

commit 8530e4e20ec2355c273f4dba9002969e68275e5f upstream.

The "run_isr" flag is used for preventing the driver from
calling the interrupt service routine in its runtime resume
callback when the driver is expecting completion to a
command, but what that basically does is that it hides the
real problem. The real problem is that the controller is
allowed to suspend in the middle of command execution.

As a more appropriate fix for the problem, using autosuspend
delay time that matches UCSI_TIMEOUT_MS (5s). That prevents
the controller from suspending while still in the middle of
executing a command.

This fixes a potential deadlock. Both ccg_read() and
ccg_write() are called with the mutex already taken at least
from ccg_send_command(). In ccg_read() and ccg_write, the
mutex is only acquired so that run_isr flag can be set.

Fixes: f0e4cd948b91 ("usb: typec: ucsi: ccg: add runtime pm workaround")
Cc: [email protected]
Signed-off-by: Heikki Krogerus <[email protected]>
Link: 
https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 drivers/usb/typec/ucsi/ucsi_ccg.c |   42 +++-----------------------------------
 1 file changed, 4 insertions(+), 38 deletions(-)

--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -195,7 +195,6 @@ struct ucsi_ccg {
 
        /* fw build with vendor information */
        u16 fw_build;
-       bool run_isr; /* flag to call ISR routine during resume */
        struct work_struct pm_work;
 };
 
@@ -224,18 +223,6 @@ static int ccg_read(struct ucsi_ccg *uc,
        if (quirks && quirks->max_read_len)
                max_read_len = quirks->max_read_len;
 
-       if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
-           uc->fw_version <= CCG_OLD_FW_VERSION) {
-               mutex_lock(&uc->lock);
-               /*
-                * Do not schedule pm_work to run ISR in
-                * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
-                * since we are already in ISR path.
-                */
-               uc->run_isr = false;
-               mutex_unlock(&uc->lock);
-       }
-
        pm_runtime_get_sync(uc->dev);
        while (rem_len > 0) {
                msgs[1].buf = &data[len - rem_len];
@@ -278,18 +265,6 @@ static int ccg_write(struct ucsi_ccg *uc
        msgs[0].len = len + sizeof(rab);
        msgs[0].buf = buf;
 
-       if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
-           uc->fw_version <= CCG_OLD_FW_VERSION) {
-               mutex_lock(&uc->lock);
-               /*
-                * Do not schedule pm_work to run ISR in
-                * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
-                * since we are already in ISR path.
-                */
-               uc->run_isr = false;
-               mutex_unlock(&uc->lock);
-       }
-
        pm_runtime_get_sync(uc->dev);
        status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
        if (status < 0) {
@@ -1133,7 +1108,6 @@ static int ucsi_ccg_probe(struct i2c_cli
        uc->ppm.sync = ucsi_ccg_sync;
        uc->dev = dev;
        uc->client = client;
-       uc->run_isr = true;
        mutex_init(&uc->lock);
        INIT_WORK(&uc->work, ccg_update_firmware);
        INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
@@ -1195,6 +1169,8 @@ static int ucsi_ccg_probe(struct i2c_cli
 
        pm_runtime_set_active(uc->dev);
        pm_runtime_enable(uc->dev);
+       pm_runtime_use_autosuspend(uc->dev);
+       pm_runtime_set_autosuspend_delay(uc->dev, 5000);
        pm_runtime_idle(uc->dev);
 
        return 0;
@@ -1237,7 +1213,6 @@ static int ucsi_ccg_runtime_resume(struc
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct ucsi_ccg *uc = i2c_get_clientdata(client);
-       bool schedule = true;
 
        /*
         * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
@@ -1245,17 +1220,8 @@ static int ucsi_ccg_runtime_resume(struc
         * Schedule a work to call ISR as a workaround.
         */
        if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
-           uc->fw_version <= CCG_OLD_FW_VERSION) {
-               mutex_lock(&uc->lock);
-               if (!uc->run_isr) {
-                       uc->run_isr = true;
-                       schedule = false;
-               }
-               mutex_unlock(&uc->lock);
-
-               if (schedule)
-                       schedule_work(&uc->pm_work);
-       }
+           uc->fw_version <= CCG_OLD_FW_VERSION)
+               schedule_work(&uc->pm_work);
 
        return 0;
 }


Reply via email to