mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
Merge "mhi: cntrl: qcom: Add support for fatal error processing"
This commit is contained in:
commit
bfcf7c9bd4
5 changed files with 109 additions and 11 deletions
|
|
@ -525,6 +525,22 @@ static int mhi_qcom_power_up(struct mhi_controller *mhi_cntrl)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void mhi_qcom_fatal_worker(struct work_struct *work)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = container_of(work, struct mhi_dev,
|
||||
fatal_worker);
|
||||
struct device *dev = &mhi_dev->pci_dev->dev;
|
||||
struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mhi_power_down(mhi_cntrl, true);
|
||||
|
||||
ret = mhi_qcom_power_up(mhi_cntrl);
|
||||
if (ret)
|
||||
MHI_ERR("Power up failure after SYS ERROR in PBL, ret:%d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
static int mhi_runtime_get(struct mhi_controller *mhi_cntrl, void *priv)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = priv;
|
||||
|
|
@ -569,6 +585,10 @@ static void mhi_status_cb(struct mhi_controller *mhi_cntrl,
|
|||
pm_runtime_put(dev);
|
||||
mhi_arch_mission_mode_enter(mhi_cntrl);
|
||||
break;
|
||||
case MHI_CB_FATAL_ERROR:
|
||||
MHI_CNTRL_ERR("Perform power cycle due to SYS ERROR in PBL\n");
|
||||
schedule_work(&mhi_dev->fatal_worker);
|
||||
break;
|
||||
default:
|
||||
MHI_CNTRL_LOG("Unhandled cb:0x%x\n", reason);
|
||||
}
|
||||
|
|
@ -782,6 +802,7 @@ static struct mhi_controller *mhi_register_controller(struct pci_dev *pci_dev)
|
|||
goto error_register;
|
||||
|
||||
INIT_WORK(&mhi_cntrl->reg_write_work, mhi_reg_write_work);
|
||||
INIT_WORK(&mhi_dev->fatal_worker, mhi_qcom_fatal_worker);
|
||||
|
||||
mhi_cntrl->reg_write_q = kcalloc(REG_WRITE_QUEUE_LEN,
|
||||
sizeof(*mhi_cntrl->reg_write_q),
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ struct mhi_dev {
|
|||
dma_addr_t iova_start;
|
||||
dma_addr_t iova_stop;
|
||||
enum mhi_suspend_mode suspend_mode;
|
||||
struct work_struct fatal_worker;
|
||||
|
||||
/* hardware info */
|
||||
u32 serial_num;
|
||||
|
|
|
|||
|
|
@ -1967,7 +1967,8 @@ static int mhi_driver_remove(struct device *dev)
|
|||
MHI_CH_STATE_DISABLED,
|
||||
MHI_CH_STATE_DISABLED
|
||||
};
|
||||
int dir;
|
||||
int dir, ret;
|
||||
bool interrupted = false;
|
||||
|
||||
/* control device has no work to do */
|
||||
if (mhi_dev->dev_type == MHI_CONTROLLER_TYPE)
|
||||
|
|
@ -1975,11 +1976,11 @@ static int mhi_driver_remove(struct device *dev)
|
|||
|
||||
MHI_LOG("Removing device for chan:%s\n", mhi_dev->chan_name);
|
||||
|
||||
/* reset both channels */
|
||||
/* move both channels to suspended state and disallow processing */
|
||||
for (dir = 0; dir < 2; dir++) {
|
||||
mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan;
|
||||
|
||||
if (!mhi_chan)
|
||||
if (!mhi_chan || mhi_chan->offload_ch)
|
||||
continue;
|
||||
|
||||
/* wake all threads waiting for completion */
|
||||
|
|
@ -1988,15 +1989,45 @@ static int mhi_driver_remove(struct device *dev)
|
|||
complete_all(&mhi_chan->completion);
|
||||
write_unlock_irq(&mhi_chan->lock);
|
||||
|
||||
/* move channel state to disable, no more processing */
|
||||
mutex_lock(&mhi_chan->mutex);
|
||||
write_lock_irq(&mhi_chan->lock);
|
||||
if (mhi_chan->ch_state != MHI_CH_STATE_DISABLED) {
|
||||
ch_state[dir] = mhi_chan->ch_state;
|
||||
mhi_chan->ch_state = MHI_CH_STATE_SUSPENDED;
|
||||
}
|
||||
write_unlock_irq(&mhi_chan->lock);
|
||||
mutex_unlock(&mhi_chan->mutex);
|
||||
}
|
||||
|
||||
/* wait for each channel to close and reset both channels */
|
||||
for (dir = 0; dir < 2; dir++) {
|
||||
mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan;
|
||||
|
||||
if (!mhi_chan || mhi_chan->offload_ch)
|
||||
continue;
|
||||
|
||||
/* unbind request from userspace, wait for channel reset */
|
||||
if (!(mhi_cntrl->power_down ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) &&
|
||||
ch_state[dir] != MHI_CH_STATE_DISABLED && !interrupted) {
|
||||
MHI_ERR("Channel %s busy, wait for it to be reset\n",
|
||||
mhi_dev->chan_name);
|
||||
ret = wait_event_interruptible(mhi_cntrl->state_event,
|
||||
mhi_chan->ch_state == MHI_CH_STATE_DISABLED ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state));
|
||||
if (unlikely(ret))
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
/* update channel state as an error can exit above wait */
|
||||
mutex_lock(&mhi_chan->mutex);
|
||||
|
||||
write_lock_irq(&mhi_chan->lock);
|
||||
ch_state[dir] = mhi_chan->ch_state;
|
||||
mhi_chan->ch_state = MHI_CH_STATE_SUSPENDED;
|
||||
write_unlock_irq(&mhi_chan->lock);
|
||||
|
||||
/* reset the channel */
|
||||
if (!mhi_chan->offload_ch)
|
||||
/* reset channel if it was left enabled */
|
||||
if (ch_state[dir] != MHI_CH_STATE_DISABLED)
|
||||
mhi_reset_chan(mhi_cntrl, mhi_chan);
|
||||
|
||||
mutex_unlock(&mhi_chan->mutex);
|
||||
|
|
@ -2014,7 +2045,7 @@ static int mhi_driver_remove(struct device *dev)
|
|||
|
||||
mutex_lock(&mhi_chan->mutex);
|
||||
|
||||
if (ch_state[dir] == MHI_CH_STATE_ENABLED &&
|
||||
if (ch_state[dir] != MHI_CH_STATE_DISABLED &&
|
||||
!mhi_chan->offload_ch)
|
||||
mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan);
|
||||
|
||||
|
|
|
|||
|
|
@ -1259,6 +1259,22 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
|
|||
st = MHI_ST_TRANSITION_MISSION_MODE;
|
||||
break;
|
||||
case MHI_EE_RDDM:
|
||||
if (mhi_cntrl->ee == MHI_EE_RDDM ||
|
||||
mhi_cntrl->power_down)
|
||||
break;
|
||||
|
||||
MHI_ERR("RDDM event occurred!\n");
|
||||
write_lock_irq(&mhi_cntrl->pm_lock);
|
||||
mhi_cntrl->ee = MHI_EE_RDDM;
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
|
||||
/* notify critical clients */
|
||||
mhi_control_error(mhi_cntrl);
|
||||
|
||||
mhi_cntrl->status_cb(mhi_cntrl,
|
||||
mhi_cntrl->priv_data,
|
||||
MHI_CB_EE_RDDM);
|
||||
wake_up_all(&mhi_cntrl->state_event);
|
||||
break;
|
||||
default:
|
||||
MHI_ERR("Unhandled EE event:%s\n",
|
||||
|
|
@ -2038,19 +2054,22 @@ static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl,
|
|||
{
|
||||
int ret;
|
||||
bool in_mission_mode = false;
|
||||
bool notify = false;
|
||||
|
||||
MHI_LOG("Entered: unprepare channel:%d\n", mhi_chan->chan);
|
||||
|
||||
/* no more processing events for this channel */
|
||||
mutex_lock(&mhi_chan->mutex);
|
||||
write_lock_irq(&mhi_chan->lock);
|
||||
if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) {
|
||||
if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED &&
|
||||
mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) {
|
||||
MHI_LOG("chan:%d is already disabled\n", mhi_chan->chan);
|
||||
write_unlock_irq(&mhi_chan->lock);
|
||||
mutex_unlock(&mhi_chan->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mhi_chan->ch_state == MHI_CH_STATE_SUSPENDED)
|
||||
notify = true;
|
||||
mhi_chan->ch_state = MHI_CH_STATE_DISABLED;
|
||||
write_unlock_irq(&mhi_chan->lock);
|
||||
|
||||
|
|
@ -2091,6 +2110,10 @@ error_invalid_state:
|
|||
if (!mhi_chan->offload_ch) {
|
||||
mhi_reset_chan(mhi_cntrl, mhi_chan);
|
||||
mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan);
|
||||
|
||||
/* notify waiters to proceed with unbinding channel */
|
||||
if (notify)
|
||||
wake_up_all(&mhi_cntrl->state_event);
|
||||
}
|
||||
MHI_LOG("chan:%d successfully resetted\n", mhi_chan->chan);
|
||||
mutex_unlock(&mhi_chan->mutex);
|
||||
|
|
@ -2361,7 +2384,8 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl,
|
|||
mhi_chan->chan, cmd == MHI_CMD_START_CHAN ? "START" : "STOP");
|
||||
|
||||
/* if channel is not active state state do not allow to state change */
|
||||
if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) {
|
||||
if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED &&
|
||||
mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) {
|
||||
ret = -EINVAL;
|
||||
MHI_LOG("channel:%d is not in active state, ch_state%d\n",
|
||||
mhi_chan->chan, mhi_chan->ch_state);
|
||||
|
|
|
|||
|
|
@ -1487,6 +1487,26 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (mhi_cntrl->rddm_supported) {
|
||||
if (mhi_get_exec_env(mhi_cntrl) == MHI_EE_RDDM &&
|
||||
!mhi_cntrl->power_down) {
|
||||
mhi_cntrl->ee = MHI_EE_RDDM;
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
|
||||
MHI_ERR("RDDM event occurred!\n");
|
||||
|
||||
/* notify critical clients with early notifications */
|
||||
mhi_control_error(mhi_cntrl);
|
||||
|
||||
mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data,
|
||||
MHI_CB_EE_RDDM);
|
||||
wake_up_all(&mhi_cntrl->state_event);
|
||||
|
||||
tasklet_enable(&mhi_cntrl->mhi_event->task);
|
||||
goto exit_pm_fast_resume;
|
||||
}
|
||||
}
|
||||
|
||||
/* restore the states */
|
||||
mhi_cntrl->pm_state = mhi_cntrl->saved_pm_state;
|
||||
mhi_cntrl->dev_state = mhi_cntrl->saved_dev_state;
|
||||
|
|
@ -1530,6 +1550,7 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
|
|||
/* schedules worker if any special purpose events need to be handled */
|
||||
mhi_special_events_pending(mhi_cntrl);
|
||||
|
||||
exit_pm_fast_resume:
|
||||
MHI_LOG("Exit with pm_state:%s dev_state:%s\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state),
|
||||
TO_MHI_STATE_STR(mhi_cntrl->dev_state));
|
||||
|
|
|
|||
Loading…
Reference in a new issue