diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 9d149e45b87a..67d9eb57b8a1 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -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); diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index f4bb8b8e4972..8edd644026af 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -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); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index cdae828291cb..8c0983231f37 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -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; } diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index f734253a147c..1b1717f5ed91 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -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), diff --git a/include/linux/mhi.h b/include/linux/mhi.h index a905eec19154..59339d0b2632 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -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 */