Re: [PATCH 4/8] platform: arm64: qcom-hamoa-ec: Add fan RPM query and LUT calibration
Anvesh Jain P <[email protected]> Wed, 5 Aug 2026 18:45:56 +0530
| Newsgroups | dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-devicetree |
|---|---|
| Message-ID | <[email protected]> |
On 7/28/2026 11:45 PM, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: > - [High] Race condition between suspend/remove paths and `fan_calib_work_fn` can cause a 10 to 20-second hang. > - [High] `psy_work` can be queued and executed while the device is in suspend, leading to I2C transfer failures. > -- > > --- Patch [4]: [PATCH 4/8] platform: arm64: qcom-hamoa-ec: Add fan RPM query and LUT calibration --- > commit e49733d2c63b28585a159eb3f465f9613c0aec7d > Author: Anvesh Jain P <[email protected]> > > platform: arm64: qcom-hamoa-ec: Add fan RPM query and LUT calibration > > This commit adds EC command definitions and handler functions for querying > fan RPM and programming per-fan LUTs mapping SoC temperature to target RPM. > It implements a runtime calibration work item to determine the maximum RPM, > and programs the LUT once calibration finishes and upon power-supply changes. > >> diff --git a/drivers/platform/arm64/qcom-hamoa-ec.c b/drivers/platform/arm64/qcom-hamoa-ec.c >> index f6ff77d4e8f69..d0c45d9970eee 100644 >> --- a/drivers/platform/arm64/qcom-hamoa-ec.c >> +++ b/drivers/platform/arm64/qcom-hamoa-ec.c > [ ... ] >> @@ -665,6 +1097,49 @@ static void qcom_ec_soc_tj_work_fn(struct work_struct *work) >> queue_delayed_work(system_percpu_wq, &ec->soc_tj_work, EC_SOC_TJ_TEMP_POLL_JIFFIES); >> } >> >> +static void qcom_ec_fan_calib_work_fn(struct work_struct *work) >> +{ >> + struct qcom_ec *ec = container_of(work, struct qcom_ec, fan_calib_work); >> + struct device *dev = &ec->client->dev; >> + int i, ret; >> + >> + reinit_completion(&ec->calib_abort); > > [Severity: High] > Can this race with the suspend or remove paths and cause a long delay? > > If qcom_ec_fan_calib_work_fn() begins executing concurrently with > qcom_ec_suspend() or qcom_ec_remove(), the suspend/remove thread calls > complete_all(&ec->calib_abort) to signal the worker to abort. > > However, if the worker executes reinit_completion() immediately after the > suspend thread's complete_all(), the abort signal is erased. The suspend > thread then blocks in cancel_work_sync(), waiting for the worker to finish, > and the worker will block in wait_for_completion_interruptible_timeout() > for the full timeout per fan (up to 10-20 seconds total). > I'll guard against this, probably by checking completion state before reinit or using a separate abort flag instead of relying on reinit_completion() alone. >> + >> + mutex_lock(&ec->io_lock); >> + ec->calibrating = true; >> + mutex_unlock(&ec->io_lock); >> + > [ ... ] >> @@ -690,7 +1169,16 @@ static int qcom_ec_suspend(struct device *dev) >> struct qcom_ec *ec = i2c_get_clientdata(client); >> int ret; >> >> - disable_delayed_work_sync(&ec->soc_tj_work); >> + if (ec->lut_cfg && ec->thermal_cap.fan_cnt) { >> + complete_all(&ec->calib_abort); >> + cancel_work_sync(&ec->fan_calib_work); >> + } >> + >> + if (ec->lut_cfg) >> + cancel_work_sync(&ec->psy_work); > > [Severity: High] > Does this allow psy_work to be re-queued and executed during suspend? > > While cancel_work_sync() stops currently pending work, the system-wide > power supply notifier qcom_ec_psy_notifier() is not unregistered during > suspend. > > If a power supply event occurs during the suspend process after > cancel_work_sync() has run, the notifier can immediately queue psy_work > back to the non-freezable system_long_wq. > > This could cause the work to run and attempt I2C transfers while the > I2C controller is suspended or the EC is in Modern Standby, potentially > leading to bus lockups or suspend failures. > I'll switch that to disable_work_sync() so the notifier can't requeue it mid-suspend. >> + >> + if (ec->lut_cfg && ec->lut_cfg->send_soc_tj) >> + disable_delayed_work_sync(&ec->soc_tj_work); >> >> mutex_lock(&ec->io_lock); >> ret = i2c_smbus_write_byte_data(client, EC_MODERN_STANDBY_CMD, > -- Best Regards, Anvesh