Loading drivers/bus/mhi/core/mhi_init.c +14 −7 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/debugfs.h> #include <linux/device.h> Loading Loading @@ -1018,7 +1018,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, if (!mhi_cntrl->mhi_event) return -ENOMEM; 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; Loading Loading @@ -1101,13 +1101,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; } Loading Loading @@ -1393,9 +1393,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); Loading @@ -1408,7 +1414,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) Loading Loading @@ -1516,6 +1522,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) error_alloc_dev: kfree(mhi_cntrl->mhi_cmd); destroy_workqueue(mhi_cntrl->special_wq); error_alloc_cmd: vfree(mhi_cntrl->mhi_chan); Loading drivers/bus/mhi/core/mhi_internal.h +3 −3 Original line number Diff line number Diff line Loading @@ -550,10 +550,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 { Loading Loading @@ -769,8 +769,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); Loading drivers/bus/mhi/core/mhi_main.c +1 −1 Original line number Diff line number Diff line Loading @@ -1762,7 +1762,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; } Loading drivers/bus/mhi/core/mhi_pm.c +19 −14 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ #include <linux/mhi.h> #include "mhi_internal.h" static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl); /* * Not all MHI states transitions are sync transitions. Linkdown, SSR, and * shutdown can happen anytime asynchronously. This function will transition to Loading Loading @@ -525,6 +527,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) mhi_timesync_log(mhi_cntrl); mhi_special_events_pending(mhi_cntrl); MHI_LOG("Adding new devices\n"); /* add supported devices */ Loading Loading @@ -643,7 +647,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); mhi_cntrl->force_m3_done = false; Loading Loading @@ -785,18 +789,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; } Loading @@ -804,11 +809,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", Loading @@ -816,8 +821,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); } Loading Loading @@ -1380,11 +1385,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; } Loading Loading @@ -1453,8 +1458,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), Loading include/linux/mhi.h +5 −4 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _MHI_H_ #define _MHI_H_ Loading Loading @@ -306,7 +306,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; Loading Loading @@ -346,8 +346,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 Loading
drivers/bus/mhi/core/mhi_init.c +14 −7 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/debugfs.h> #include <linux/device.h> Loading Loading @@ -1018,7 +1018,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, if (!mhi_cntrl->mhi_event) return -ENOMEM; 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; Loading Loading @@ -1101,13 +1101,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; } Loading Loading @@ -1393,9 +1393,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); Loading @@ -1408,7 +1414,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) Loading Loading @@ -1516,6 +1522,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) error_alloc_dev: kfree(mhi_cntrl->mhi_cmd); destroy_workqueue(mhi_cntrl->special_wq); error_alloc_cmd: vfree(mhi_cntrl->mhi_chan); Loading
drivers/bus/mhi/core/mhi_internal.h +3 −3 Original line number Diff line number Diff line Loading @@ -550,10 +550,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 { Loading Loading @@ -769,8 +769,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); Loading
drivers/bus/mhi/core/mhi_main.c +1 −1 Original line number Diff line number Diff line Loading @@ -1762,7 +1762,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; } Loading
drivers/bus/mhi/core/mhi_pm.c +19 −14 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ #include <linux/mhi.h> #include "mhi_internal.h" static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl); /* * Not all MHI states transitions are sync transitions. Linkdown, SSR, and * shutdown can happen anytime asynchronously. This function will transition to Loading Loading @@ -525,6 +527,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) mhi_timesync_log(mhi_cntrl); mhi_special_events_pending(mhi_cntrl); MHI_LOG("Adding new devices\n"); /* add supported devices */ Loading Loading @@ -643,7 +647,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); mhi_cntrl->force_m3_done = false; Loading Loading @@ -785,18 +789,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; } Loading @@ -804,11 +809,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", Loading @@ -816,8 +821,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); } Loading Loading @@ -1380,11 +1385,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; } Loading Loading @@ -1453,8 +1458,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), Loading
include/linux/mhi.h +5 −4 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _MHI_H_ #define _MHI_H_ Loading Loading @@ -306,7 +306,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; Loading Loading @@ -346,8 +346,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