bus: mhi: host: Add support for processing of sleepable events

Processing of some events requires the use of a sleeping function.
In order to handle those events, work is queued using high priority
workqueue. Sleepable events also require use of a dedicated event
ring.

Replaced 'TO_MHI_STATE_STR' with 'mhi_state_str' to aid in
compilation.

Change-Id: I3c42bc5b33b179de79911f8ec21b9a351116a112
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Signed-off-by: Lazarus Motha <quic_lmotha@quicinc.com>
This commit is contained in:
Hemant Kumar 2020-06-16 15:01:41 -07:00 committed by Gerrit - the friendly Code Review server
parent 93258369b2
commit 04d4e7ae5c
5 changed files with 69 additions and 6 deletions

View File

@ -946,11 +946,13 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
mhi_event->mhi_cntrl = mhi_cntrl;
spin_lock_init(&mhi_event->lock);
if (mhi_event->data_type == MHI_ER_CTRL)
tasklet_init(&mhi_event->task, mhi_ctrl_ev_task,
(ulong)mhi_event);
if (mhi_event->priority == MHI_ER_PRIORITY_HI_SLEEP)
INIT_WORK(&mhi_event->work, mhi_process_ev_work);
else
tasklet_init(&mhi_event->task, mhi_ev_task,
tasklet_init(&mhi_event->task,
(mhi_event->data_type == MHI_ER_CTRL) ?
mhi_ctrl_ev_task : mhi_ev_task,
(ulong)mhi_event);
}

View File

@ -201,6 +201,7 @@ struct mhi_event {
struct mhi_ring ring;
struct db_cfg db_cfg;
struct tasklet_struct task;
struct work_struct work;
spinlock_t lock;
int (*process_event)(struct mhi_controller *mhi_cntrl,
struct mhi_event *mhi_event,
@ -359,6 +360,8 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl,
/* Event processing methods */
void mhi_ctrl_ev_task(unsigned long data);
void mhi_ev_task(unsigned long data);
void mhi_process_ev_work(struct work_struct *work);
void mhi_process_sleeping_events(struct mhi_controller *mhi_cntrl);
int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
struct mhi_event *mhi_event, u32 event_quota);
int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,

View File

@ -426,6 +426,30 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
}
}
void mhi_process_sleeping_events(struct mhi_controller *mhi_cntrl)
{
struct mhi_event *mhi_event;
struct mhi_event_ctxt *er_ctxt;
struct mhi_ring *ev_ring;
int i;
mhi_event = mhi_cntrl->mhi_event;
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
if (mhi_event->offload_ev || mhi_event->priority !=
MHI_ER_PRIORITY_HI_SLEEP)
continue;
er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
ev_ring = &mhi_event->ring;
/* Only proceed if event ring has pending events */
if (ev_ring->rp == mhi_to_virtual(ev_ring, er_ctxt->rp))
continue;
queue_work(mhi_cntrl->hiprio_wq, &mhi_event->work);
}
}
irqreturn_t mhi_irq_handler(int irq_number, void *priv)
{
struct mhi_event *mhi_event = priv;
@ -467,6 +491,9 @@ irqreturn_t mhi_irq_handler(int irq_number, void *priv)
case MHI_ER_PRIORITY_DEFAULT_NOSLEEP:
tasklet_schedule(&mhi_event->task);
break;
case MHI_ER_PRIORITY_HI_SLEEP:
queue_work(mhi_cntrl->hiprio_wq, &mhi_event->work);
break;
default:
dev_dbg(dev, "skip unknown priority event\n");
break;
@ -1095,6 +1122,24 @@ void mhi_ctrl_ev_task(unsigned long data)
}
}
void mhi_process_ev_work(struct work_struct *work)
{
struct mhi_event *mhi_event = container_of(work, struct mhi_event,
work);
struct mhi_controller *mhi_cntrl = mhi_event->mhi_cntrl;
struct device *dev = mhi_cntrl->cntrl_dev;
dev_dbg(dev, "Enter with pm_state:%s MHI_STATE:%s ee:%s\n",
to_mhi_pm_state_str(mhi_cntrl->pm_state),
mhi_state_str(mhi_cntrl->dev_state),
TO_MHI_EXEC_STR(mhi_cntrl->ee));
if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state)))
return;
mhi_event->process_event(mhi_cntrl, mhi_event, U32_MAX);
}
static bool mhi_is_ring_full(struct mhi_controller *mhi_cntrl,
struct mhi_ring *ring)
{

View File

@ -432,6 +432,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)
read_unlock_bh(&mhi_cntrl->pm_lock);
mhi_process_sleeping_events(mhi_cntrl);
/*
* The MHI devices are only created when the client device switches its
* Execution Environment (EE) to either SBL or AMSS states
@ -497,7 +499,10 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
if (mhi_event->offload_ev)
continue;
disable_irq(mhi_cntrl->irq[mhi_event->irq]);
tasklet_kill(&mhi_event->task);
if (mhi_event->priority == MHI_ER_PRIORITY_HI_SLEEP)
cancel_work_sync(&mhi_event->work);
else
tasklet_kill(&mhi_event->task);
}
/* Release lock and wait for all pending threads to complete */
@ -630,7 +635,10 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
if (mhi_event->offload_ev)
continue;
tasklet_kill(&mhi_event->task);
if (mhi_event->priority == MHI_ER_PRIORITY_HI_SLEEP)
cancel_work_sync(&mhi_event->work);
else
tasklet_kill(&mhi_event->task);
}
/* Release lock and wait for all pending threads to complete */
@ -766,6 +774,9 @@ void mhi_pm_st_worker(struct work_struct *work)
write_lock_irq(&mhi_cntrl->pm_lock);
mhi_cntrl->ee = MHI_EE_SBL;
write_unlock_irq(&mhi_cntrl->pm_lock);
mhi_process_sleeping_events(mhi_cntrl);
/*
* The MHI devices are only created when the client
* device switches its Execution Environment (EE) to

View File

@ -202,10 +202,12 @@ enum mhi_er_data_type {
* enum mhi_er_priority - Event ring processing priority
* @MHI_ER_PRIORITY_DEFAULT_NOSLEEP: processed by tasklet
* @MHI_ER_PRIORITY_HI_NOSLEEP: processed by hi-priority tasklet
* @MHI_ER_PRIORITY_HI_SLEEP: processed by hi-priority wq
*/
enum mhi_er_priority {
MHI_ER_PRIORITY_DEFAULT_NOSLEEP,
MHI_ER_PRIORITY_HI_NOSLEEP,
MHI_ER_PRIORITY_HI_SLEEP,
};
/**