diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index fb2e3c2f5b03..c02eee9886c7 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -797,6 +797,7 @@ int mhi_process_tsync_ev_ring(struct mhi_controller *mhi_cntrl, struct mhi_event *mhi_event, u32 event_quota); int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, struct mhi_event *mhi_event, u32 event_quota); +void mhi_special_dbs_pending(struct mhi_controller *mhi_cntrl); int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, enum MHI_CMD cmd); int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index e589777e6bcb..2315552b831b 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1479,7 +1479,8 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, struct mhi_event_ctxt *er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; struct mhi_link_info link_info, *cur_info = &mhi_cntrl->mhi_link_info; - int result, ret = 0; + u32 result = MHI_BW_SCALE_NACK; + int ret = 0; spin_lock_bh(&mhi_event->lock); dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); @@ -1527,17 +1528,23 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, mutex_lock(&mhi_cntrl->pm_mutex); ret = mhi_cntrl->bw_scale(mhi_cntrl, &link_info); - if (!ret) + if (!ret) { *cur_info = link_info; + result = 0; + } - result = ret ? MHI_BW_SCALE_NACK : 0; - - read_lock_bh(&mhi_cntrl->pm_lock); - if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) + write_lock_bh(&mhi_cntrl->pm_lock); + cur_info->last_response = MHI_BW_SCALE_RESULT(result, + link_info.sequence_num); + if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) { mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bw_scale_db, 0, - MHI_BW_SCALE_RESULT(result, - link_info.sequence_num)); - read_unlock_bh(&mhi_cntrl->pm_lock); + cur_info->last_response); + cur_info->last_response = 0; + } else { + MHI_VERB("Cached response to BW_REQ seq: %d, ret: %d\n", + link_info.sequence_num, ret); + } + write_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); @@ -1549,6 +1556,20 @@ exit_bw_scale_process: return ret; } +void mhi_special_dbs_pending(struct mhi_controller *mhi_cntrl) +{ + struct mhi_link_info *link_info = &mhi_cntrl->mhi_link_info; + + /* last_response cannot be empty as sequence numbers are non-zero */ + if (mhi_cntrl->bw_scale && link_info->last_response) { + mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->bw_scale_db, 0, + link_info->last_response); + MHI_VERB("Completed cached BW switch response: %d\n", + link_info->last_response); + link_info->last_response = 0; + } +} + void mhi_ev_task(unsigned long data) { struct mhi_event *mhi_event = (struct mhi_event *)data; diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 75bf575b7d7a..06a970d47631 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -376,6 +376,9 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) if (mhi_cmd->ring.rp != mhi_cmd->ring.wp) mhi_ring_cmd_db(mhi_cntrl, mhi_cmd); spin_unlock_irq(&mhi_cmd->lock); + + /* ring special doorbells for controllers in legacy mode */ + mhi_special_dbs_pending(mhi_cntrl); } /* ring channel db registers */ diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 1ff821e8af24..1988d2ea1fd4 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -132,11 +132,13 @@ enum mhi_dev_state { * target_link_speed - as defined by TLS bits in LinkControl reg * target_link_width - as defined by NLW bits in LinkStatus reg * sequence_num - used by device to track bw requests sent to host + * last_response - used by host to cache response to the last bw switch request */ struct mhi_link_info { unsigned int target_link_speed; unsigned int target_link_width; int sequence_num; + u32 last_response; }; /**