mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 05:39:54 -04:00
mhi: core: prioritize handling special purpose events
Some device requested special purpose events can take a long time to get processed on host. Fix that by moving to dedicated worker thread. Change-Id: Ibfe7c56b85cb58b9ee67e41ea1139702d475ffee Signed-off-by: Bhaumik Bhatt <bbhatt@codeaurora.org>
This commit is contained in:
parent
b5aa51711d
commit
e3dc5ad381
5 changed files with 36 additions and 26 deletions
|
|
@ -978,7 +978,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl,
|
|||
goto err_put;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&mhi_cntrl->lp_ev_rings);
|
||||
INIT_LIST_HEAD(&mhi_cntrl->sp_ev_rings);
|
||||
|
||||
/* populate ev ring */
|
||||
mhi_event = mhi_cntrl->mhi_event;
|
||||
|
|
@ -1061,13 +1061,13 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl,
|
|||
"mhi,offload");
|
||||
|
||||
/*
|
||||
* low priority events are handled in a separate worker thread
|
||||
* special purpose events are handled in a separate kthread
|
||||
* to allow for sleeping functions to be called.
|
||||
*/
|
||||
if (!mhi_event->offload_ev) {
|
||||
if (IS_MHI_ER_PRIORITY_LOW(mhi_event))
|
||||
if (IS_MHI_ER_PRIORITY_SPECIAL(mhi_event))
|
||||
list_add_tail(&mhi_event->node,
|
||||
&mhi_cntrl->lp_ev_rings);
|
||||
&mhi_cntrl->sp_ev_rings);
|
||||
else
|
||||
mhi_event->request_irq = true;
|
||||
}
|
||||
|
|
@ -1360,9 +1360,15 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
|
|||
spin_lock_init(&mhi_cntrl->transition_lock);
|
||||
spin_lock_init(&mhi_cntrl->wlock);
|
||||
INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker);
|
||||
INIT_WORK(&mhi_cntrl->low_priority_worker, mhi_low_priority_worker);
|
||||
init_waitqueue_head(&mhi_cntrl->state_event);
|
||||
|
||||
mhi_cntrl->special_wq = alloc_ordered_workqueue("mhi_special_w",
|
||||
WQ_MEM_RECLAIM | WQ_HIGHPRI);
|
||||
if (!mhi_cntrl->special_wq)
|
||||
goto error_alloc_cmd;
|
||||
|
||||
INIT_WORK(&mhi_cntrl->special_work, mhi_special_purpose_work);
|
||||
|
||||
mhi_cmd = mhi_cntrl->mhi_cmd;
|
||||
for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++)
|
||||
spin_lock_init(&mhi_cmd->lock);
|
||||
|
|
@ -1375,7 +1381,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
|
|||
mhi_event->mhi_cntrl = mhi_cntrl;
|
||||
spin_lock_init(&mhi_event->lock);
|
||||
|
||||
if (IS_MHI_ER_PRIORITY_LOW(mhi_event))
|
||||
if (IS_MHI_ER_PRIORITY_SPECIAL(mhi_event))
|
||||
continue;
|
||||
|
||||
if (mhi_event->data_type == MHI_ER_CTRL_ELEMENT_TYPE)
|
||||
|
|
@ -1463,6 +1469,7 @@ error_add_dev:
|
|||
|
||||
error_alloc_dev:
|
||||
kfree(mhi_cntrl->mhi_cmd);
|
||||
destroy_workqueue(mhi_cntrl->special_wq);
|
||||
|
||||
error_alloc_cmd:
|
||||
vfree(mhi_cntrl->mhi_chan);
|
||||
|
|
|
|||
|
|
@ -539,10 +539,10 @@ enum MHI_ER_TYPE {
|
|||
enum mhi_er_priority {
|
||||
MHI_ER_PRIORITY_HIGH,
|
||||
MHI_ER_PRIORITY_MEDIUM,
|
||||
MHI_ER_PRIORITY_LOW,
|
||||
MHI_ER_PRIORITY_SPECIAL,
|
||||
};
|
||||
|
||||
#define IS_MHI_ER_PRIORITY_LOW(ev) (ev->priority >= MHI_ER_PRIORITY_LOW)
|
||||
#define IS_MHI_ER_PRIORITY_SPECIAL(ev) (ev->priority >= MHI_ER_PRIORITY_SPECIAL)
|
||||
#define IS_MHI_ER_PRIORITY_HIGH(ev) (ev->priority == MHI_ER_PRIORITY_HIGH)
|
||||
|
||||
enum mhi_er_data_type {
|
||||
|
|
@ -747,8 +747,8 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
|
|||
enum MHI_ST_TRANSITION state);
|
||||
void mhi_pm_st_worker(struct work_struct *work);
|
||||
void mhi_fw_load_worker(struct work_struct *work);
|
||||
void mhi_special_purpose_work(struct work_struct *work);
|
||||
void mhi_process_sys_err(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_low_priority_worker(struct work_struct *work);
|
||||
int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_ctrl_ev_task(unsigned long data);
|
||||
int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl);
|
||||
|
|
|
|||
|
|
@ -1724,7 +1724,7 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev)
|
|||
MHI_VERB("Exit\n");
|
||||
|
||||
if (MHI_IN_MISSION_MODE(mhi_cntrl->ee))
|
||||
schedule_work(&mhi_cntrl->low_priority_worker);
|
||||
queue_work(mhi_cntrl->special_wq, &mhi_cntrl->special_work);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
|
|||
|
||||
MHI_LOG("Waiting for all pending threads to complete\n");
|
||||
wake_up_all(&mhi_cntrl->state_event);
|
||||
flush_work(&mhi_cntrl->low_priority_worker);
|
||||
flush_work(&mhi_cntrl->special_work);
|
||||
|
||||
/* remove support for time sync */
|
||||
mhi_destroy_timesync(mhi_cntrl);
|
||||
|
|
@ -778,18 +778,19 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mhi_low_priority_events_pending(struct mhi_controller *mhi_cntrl)
|
||||
static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_event *mhi_event;
|
||||
|
||||
list_for_each_entry(mhi_event, &mhi_cntrl->lp_ev_rings, node) {
|
||||
list_for_each_entry(mhi_event, &mhi_cntrl->sp_ev_rings, node) {
|
||||
struct mhi_event_ctxt *er_ctxt =
|
||||
&mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
|
||||
struct mhi_ring *ev_ring = &mhi_event->ring;
|
||||
|
||||
spin_lock_bh(&mhi_event->lock);
|
||||
if (ev_ring->rp != mhi_to_virtual(ev_ring, er_ctxt->rp)) {
|
||||
schedule_work(&mhi_cntrl->low_priority_worker);
|
||||
queue_work(mhi_cntrl->special_wq,
|
||||
&mhi_cntrl->special_work);
|
||||
spin_unlock_bh(&mhi_event->lock);
|
||||
break;
|
||||
}
|
||||
|
|
@ -797,11 +798,11 @@ static void mhi_low_priority_events_pending(struct mhi_controller *mhi_cntrl)
|
|||
}
|
||||
}
|
||||
|
||||
void mhi_low_priority_worker(struct work_struct *work)
|
||||
void mhi_special_purpose_work(struct work_struct *work)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = container_of(work,
|
||||
struct mhi_controller,
|
||||
low_priority_worker);
|
||||
special_work);
|
||||
struct mhi_event *mhi_event;
|
||||
|
||||
MHI_VERB("Enter with pm_state:%s MHI_STATE:%s ee:%s\n",
|
||||
|
|
@ -809,8 +810,8 @@ void mhi_low_priority_worker(struct work_struct *work)
|
|||
TO_MHI_STATE_STR(mhi_cntrl->dev_state),
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee));
|
||||
|
||||
/* check low priority event rings and process events */
|
||||
list_for_each_entry(mhi_event, &mhi_cntrl->lp_ev_rings, node)
|
||||
/* check special purpose event rings and process events */
|
||||
list_for_each_entry(mhi_event, &mhi_cntrl->sp_ev_rings, node)
|
||||
mhi_event->process_event(mhi_cntrl, mhi_event, U32_MAX);
|
||||
}
|
||||
|
||||
|
|
@ -1377,11 +1378,11 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
|
|||
|
||||
/*
|
||||
* If MHI on host is in suspending/suspended state, we do not process
|
||||
* any low priority requests, for example, bandwidth scaling events
|
||||
* from the device. Check for low priority event rings and handle the
|
||||
* pending events upon resume.
|
||||
* any special purpose requests, for example, bandwidth scaling events
|
||||
* from the device. Check for special purpose event rings and handle
|
||||
* the pending events upon resume.
|
||||
*/
|
||||
mhi_low_priority_events_pending(mhi_cntrl);
|
||||
mhi_special_events_pending(mhi_cntrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1472,8 +1473,8 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
|
|||
mhi_msi_handlr(0, mhi_event);
|
||||
}
|
||||
|
||||
/* schedules worker if any low priority events need to be handled */
|
||||
mhi_low_priority_events_pending(mhi_cntrl);
|
||||
/* schedules worker if any special purpose events need to be handled */
|
||||
mhi_special_events_pending(mhi_cntrl);
|
||||
|
||||
MHI_LOG("Exit with pm_state:%s dev_state:%s\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state),
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ struct mhi_controller {
|
|||
u32 msi_allocated;
|
||||
int *irq; /* interrupt table */
|
||||
struct mhi_event *mhi_event;
|
||||
struct list_head lp_ev_rings; /* low priority event rings */
|
||||
struct list_head sp_ev_rings; /* special purpose event rings */
|
||||
|
||||
/* cmd rings */
|
||||
struct mhi_cmd *mhi_cmd;
|
||||
|
|
@ -353,7 +353,9 @@ struct mhi_controller {
|
|||
/* worker for different state transitions */
|
||||
struct work_struct st_worker;
|
||||
struct work_struct fw_worker;
|
||||
struct work_struct low_priority_worker;
|
||||
struct work_struct special_work;
|
||||
struct workqueue_struct *special_wq;
|
||||
|
||||
wait_queue_head_t state_event;
|
||||
|
||||
/* shadow functions */
|
||||
|
|
|
|||
Loading…
Reference in a new issue