mhi: core: Extend mhi_device_get_sync_atomic() for panic cases

In case of a kernel panic, interrupts are not handled and hence,
any attempt to assert device wake and wait for an M0 state change
relying on interrupts will fail. In order to help solve this
issue for cases where the controller needs to assert device wake
in panic path, extend the mhi_device_get_sync_atomic() API and
allow it to poll the MHI STATUS register for an M0 state change.
Make the appropriate changes wherever the API is in use.

Change-Id: I920d76d1cec879c29180438072e32e18370cf8ff
Signed-off-by: Bhaumik Bhatt <bbhatt@codeaurora.org>
This commit is contained in:
Bhaumik Bhatt
2020-07-29 16:13:27 -07:00
parent 2fb2a34b60
commit f1fb19488f
3 changed files with 23 additions and 8 deletions

View File

@@ -1670,7 +1670,8 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote)
} }
EXPORT_SYMBOL(mhi_device_get_sync); EXPORT_SYMBOL(mhi_device_get_sync);
int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us) int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us,
bool in_panic)
{ {
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
@@ -1696,12 +1697,21 @@ int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us)
return 0; return 0;
} }
if (in_panic) {
while (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M0 &&
!MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) &&
timeout_us > 0) {
udelay(MHI_FORCE_WAKE_DELAY_US);
timeout_us -= MHI_FORCE_WAKE_DELAY_US;
}
} else {
while (mhi_cntrl->pm_state != MHI_PM_M0 && while (mhi_cntrl->pm_state != MHI_PM_M0 &&
!MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) && !MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) &&
timeout_us > 0) { timeout_us > 0) {
udelay(MHI_FORCE_WAKE_DELAY_US); udelay(MHI_FORCE_WAKE_DELAY_US);
timeout_us -= MHI_FORCE_WAKE_DELAY_US; timeout_us -= MHI_FORCE_WAKE_DELAY_US;
} }
}
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || timeout_us <= 0) { if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || timeout_us <= 0) {
MHI_ERR("Did not enter M0 state, cur_state:%s pm_state:%s\n", MHI_ERR("Did not enter M0 state, cur_state:%s pm_state:%s\n",

View File

@@ -3069,7 +3069,7 @@ int cnss_pci_force_wake_request_sync(struct device *dev, int timeout_us)
if (timeout_us) { if (timeout_us) {
/* Busy wait for timeout_us */ /* Busy wait for timeout_us */
return mhi_device_get_sync_atomic(mhi_ctrl->mhi_dev, return mhi_device_get_sync_atomic(mhi_ctrl->mhi_dev,
timeout_us); timeout_us, false);
} else { } else {
/* Sleep wait for mhi_ctrl->timeout_ms */ /* Sleep wait for mhi_ctrl->timeout_ms */
return mhi_device_get_sync(mhi_ctrl->mhi_dev, MHI_VOTE_DEVICE); return mhi_device_get_sync(mhi_ctrl->mhi_dev, MHI_VOTE_DEVICE);

View File

@@ -616,6 +616,7 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote);
* mhi_device_get_sync_atomic - Asserts device_wait and moves device to M0 * mhi_device_get_sync_atomic - Asserts device_wait and moves device to M0
* @mhi_dev: Device associated with the channels * @mhi_dev: Device associated with the channels
* @timeout_us: timeout, in micro-seconds * @timeout_us: timeout, in micro-seconds
* @in_panic: If requested while kernel is in panic state and no ISRs expected
* *
* The device_wake is asserted to keep device in M0 or bring it to M0. * The device_wake is asserted to keep device in M0 or bring it to M0.
* If device is not in M0 state, then this function will wait for device to * If device is not in M0 state, then this function will wait for device to
@@ -627,6 +628,8 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote);
* Clients can ignore that transition after this function returns as the device * Clients can ignore that transition after this function returns as the device
* is expected to immediately move from M2 to M0 as wake is asserted and * is expected to immediately move from M2 to M0 as wake is asserted and
* wouldn't enter low power state. * wouldn't enter low power state.
* If in_panic boolean is set, no ISRs are expected, hence this API will have to
* resort to reading the MHI status register and poll on M0 state change.
* *
* Returns: * Returns:
* 0 if operation was successful (however, M0 -> M2 -> M0 is possible later) as * 0 if operation was successful (however, M0 -> M2 -> M0 is possible later) as
@@ -634,7 +637,9 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote);
* -ETIMEDOUT is device faled to move to M0 before @timeout_us elapsed * -ETIMEDOUT is device faled to move to M0 before @timeout_us elapsed
* -EIO if the MHI state is one of the ERROR states. * -EIO if the MHI state is one of the ERROR states.
*/ */
int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us); int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev,
int timeout_us,
bool in_panic);
/** /**
* mhi_device_put - re-enable low power modes * mhi_device_put - re-enable low power modes