Loading drivers/bus/mhi/core/mhi_init.c +4 −1 Original line number Diff line number Diff line Loading @@ -348,6 +348,9 @@ void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl) } spin_unlock(&mhi_tsync->lock); if (mhi_tsync->db_response_pending) complete(&mhi_tsync->db_completion); kfree(mhi_cntrl->mhi_tsync); mhi_cntrl->mhi_tsync = NULL; mutex_unlock(&mhi_cntrl->tsync_mutex); Loading Loading @@ -1234,7 +1237,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, mhi_event->process_event = mhi_process_ctrl_ev_ring; break; case MHI_ER_TSYNC_ELEMENT_TYPE: mhi_event->process_event = mhi_process_tsync_event_ring; mhi_event->process_event = mhi_process_tsync_ev_ring; break; case MHI_ER_BW_SCALE_ELEMENT_TYPE: mhi_event->process_event = mhi_process_bw_scale_ev_ring; Loading drivers/bus/mhi/core/mhi_internal.h +6 −4 Original line number Diff line number Diff line Loading @@ -716,8 +716,6 @@ struct mhi_chan { struct tsync_node { struct list_head node; u32 sequence; u32 int_sequence; u64 local_time; u64 remote_time; struct mhi_device *mhi_dev; void (*cb_func)(struct mhi_device *mhi_dev, u32 sequence, Loading @@ -727,7 +725,11 @@ struct tsync_node { struct mhi_timesync { void __iomem *time_reg; u32 int_sequence; u64 local_time; u64 remote_time; bool db_support; bool db_response_pending; struct completion db_completion; spinlock_t lock; /* list protection */ struct list_head head; }; Loading Loading @@ -786,7 +788,7 @@ 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, struct mhi_event *mhi_event, u32 event_quota); int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl, 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); Loading drivers/bus/mhi/core/mhi_main.c +133 −87 Original line number Diff line number Diff line Loading @@ -1348,42 +1348,69 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, return count; } int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl, int mhi_process_tsync_ev_ring(struct mhi_controller *mhi_cntrl, struct mhi_event *mhi_event, u32 event_quota) { struct mhi_tre *dev_rp, *local_rp; struct mhi_tre *dev_rp; struct mhi_ring *ev_ring = &mhi_event->ring; struct mhi_event_ctxt *er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; int count = 0; u32 int_sequence, unit; u32 sequence; u64 remote_time; int ret = 0; if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) { MHI_LOG("No EV access, PM_STATE:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state)); return -EIO; spin_lock_bh(&mhi_event->lock); dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); if (ev_ring->rp == dev_rp) { spin_unlock_bh(&mhi_event->lock); goto exit_tsync_process; } dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); local_rp = ev_ring->rp; /* if rp points to base, we need to wrap it around */ if (dev_rp == ev_ring->base) dev_rp = ev_ring->base + ev_ring->len; dev_rp--; while (dev_rp != local_rp) { enum MHI_PKT_TYPE type = MHI_TRE_GET_EV_TYPE(local_rp); struct tsync_node *tsync_node; /* fast forward to currently processed element and recycle er */ ev_ring->rp = dev_rp; ev_ring->wp = dev_rp - 1; if (ev_ring->wp < ev_ring->base) ev_ring->wp = ev_ring->base + ev_ring->len - ev_ring->el_size; mhi_recycle_fwd_ev_ring_element(mhi_cntrl, ev_ring); MHI_VERB("Processing Event:0x%llx 0x%08x 0x%08x\n", local_rp->ptr, local_rp->dword[0], local_rp->dword[1]); MHI_ASSERT(MHI_TRE_GET_EV_TYPE(dev_rp) != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event"); MHI_ASSERT(type != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event"); sequence = MHI_TRE_GET_EV_TSYNC_SEQ(dev_rp); remote_time = MHI_TRE_GET_EV_TIME(dev_rp); int_sequence = MHI_TRE_GET_EV_TSYNC_SEQ(local_rp); unit = MHI_TRE_GET_EV_TSYNC_UNIT(local_rp); remote_time = MHI_TRE_GET_EV_TIME(local_rp); MHI_VERB("Received TSYNC event with seq:0x%llx time:0x%llx\n", sequence, remote_time); read_lock_bh(&mhi_cntrl->pm_lock); if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) mhi_ring_er_db(mhi_event); read_unlock_bh(&mhi_cntrl->pm_lock); spin_unlock_bh(&mhi_event->lock); mutex_lock(&mhi_cntrl->tsync_mutex); if (unlikely(mhi_tsync->int_sequence != sequence)) { MHI_ASSERT(1, "Unexpected response:0x%llx Expected:0x%llx\n", sequence, mhi_tsync->int_sequence); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); mutex_unlock(&mhi_cntrl->tsync_mutex); goto exit_tsync_process; } do { struct tsync_node *tsync_node; spin_lock(&mhi_tsync->lock); tsync_node = list_first_entry_or_null(&mhi_tsync->head, struct tsync_node, node); Loading @@ -1395,35 +1422,24 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl, list_del(&tsync_node->node); spin_unlock(&mhi_tsync->lock); /* * device may not able to process all time sync commands * host issue and only process last command it receive */ if (tsync_node->int_sequence == int_sequence) { tsync_node->cb_func(tsync_node->mhi_dev, tsync_node->sequence, tsync_node->local_time, remote_time); kfree(tsync_node); } else { mhi_tsync->local_time, remote_time); kfree(tsync_node); } } while (true); mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp = ev_ring->rp; dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); count++; } mhi_tsync->db_response_pending = false; mhi_tsync->remote_time = remote_time; complete(&mhi_tsync->db_completion); read_lock_bh(&mhi_cntrl->pm_lock); if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) mhi_ring_er_db(mhi_event); read_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); mutex_unlock(&mhi_cntrl->tsync_mutex); exit_tsync_process: MHI_VERB("exit er_index:%u\n", mhi_event->er_index); return count; return ret; } int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, Loading Loading @@ -1475,13 +1491,10 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, read_unlock_bh(&mhi_cntrl->pm_lock); spin_unlock_bh(&mhi_event->lock); atomic_inc(&mhi_cntrl->pending_pkts); ret = mhi_device_get_sync(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); if (ret) { atomic_dec(&mhi_cntrl->pending_pkts); if (ret) goto exit_bw_scale_process; } mutex_lock(&mhi_cntrl->pm_mutex); Loading @@ -1499,7 +1512,6 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, read_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); atomic_dec(&mhi_cntrl->pending_pkts); mutex_unlock(&mhi_cntrl->pm_mutex); Loading Loading @@ -2466,13 +2478,37 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; u64 local_time; int ret; mutex_lock(&mhi_cntrl->tsync_mutex); /* not all devices support time features */ if (!mhi_tsync) { ret = -EIO; goto error_unlock; if (!mhi_tsync) return -EINVAL; if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) { MHI_ERR("MHI is not in active state, pm_state:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state)); return -EIO; } mutex_lock(&mhi_cntrl->tsync_mutex); /* return times from last async request completion */ if (mhi_tsync->db_response_pending) { local_time = mhi_tsync->local_time; mutex_unlock(&mhi_cntrl->tsync_mutex); ret = wait_for_completion_timeout(&mhi_tsync->db_completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || !ret) { MHI_ERR("Pending DB request did not complete, abort\n"); return -EAGAIN; } *t_host = local_time; *t_dev = mhi_tsync->remote_time; return 0; } /* bring to M0 state */ Loading Loading @@ -2542,17 +2578,16 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; struct tsync_node *tsync_node; int ret; int ret = 0; /* not all devices support all time features */ if (!mhi_tsync || !mhi_tsync->db_support) return -EINVAL; mutex_lock(&mhi_cntrl->tsync_mutex); if (!mhi_tsync || !mhi_tsync->db_support) { ret = -EIO; goto error_unlock; } /* tsync db can only be rung in M0 state */ ret = __mhi_device_get_sync(mhi_cntrl); ret = mhi_device_get_sync(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); if (ret) goto error_unlock; Loading @@ -2566,6 +2601,10 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, } read_unlock_bh(&mhi_cntrl->pm_lock); MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state), TO_MHI_STATE_STR(mhi_cntrl->dev_state)); /* * technically we can use GFP_KERNEL, but wants to avoid * # of times scheduling out Loading @@ -2576,15 +2615,17 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, goto error_no_mem; } mhi_tsync->int_sequence++; if (mhi_tsync->int_sequence == 0xFFFFFFFF) mhi_tsync->int_sequence = 0; tsync_node->sequence = sequence; tsync_node->int_sequence = mhi_tsync->int_sequence; tsync_node->cb_func = cb_func; tsync_node->mhi_dev = mhi_dev; if (mhi_tsync->db_response_pending) goto skip_tsync_db; mhi_tsync->int_sequence++; if (mhi_tsync->int_sequence == 0xFFFFFFFF) mhi_tsync->int_sequence = 0; /* disable link level low power modes */ ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data); if (ret) { Loading @@ -2593,10 +2634,6 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, goto error_invalid_state; } spin_lock(&mhi_tsync->lock); list_add_tail(&tsync_node->node, &mhi_tsync->head); spin_unlock(&mhi_tsync->lock); /* * time critical code, delay between these two steps should be * deterministic as possible. Loading @@ -2604,9 +2641,9 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, preempt_disable(); local_irq_disable(); tsync_node->local_time = mhi_tsync->local_time = mhi_cntrl->time_get(mhi_cntrl, mhi_cntrl->priv_data); writel_relaxed_no_log(tsync_node->int_sequence, mhi_cntrl->tsync_db); writel_relaxed_no_log(mhi_tsync->int_sequence, mhi_cntrl->tsync_db); /* write must go thru immediately */ wmb(); Loading @@ -2615,15 +2652,24 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data); ret = 0; MHI_VERB("time DB request with seq:0x%llx\n", mhi_tsync->int_sequence); mhi_tsync->db_response_pending = true; init_completion(&mhi_tsync->db_completion); skip_tsync_db: spin_lock(&mhi_tsync->lock); list_add_tail(&tsync_node->node, &mhi_tsync->head); spin_unlock(&mhi_tsync->lock); mutex_unlock(&mhi_cntrl->tsync_mutex); return 0; error_invalid_state: if (ret) kfree(tsync_node); error_no_mem: read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); error_unlock: mutex_unlock(&mhi_cntrl->tsync_mutex); return ret; Loading drivers/bus/mhi/core/mhi_pm.c +8 −2 Original line number Diff line number Diff line Loading @@ -823,6 +823,9 @@ void mhi_special_purpose_work(struct work_struct *work) TO_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; /* 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 @@ -1223,6 +1226,7 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) int ret; enum MHI_PM_STATE new_state; struct mhi_chan *itr, *tmp; struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev; read_lock_bh(&mhi_cntrl->pm_lock); if (mhi_cntrl->pm_state == MHI_PM_DISABLE) { Loading @@ -1237,7 +1241,8 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) read_unlock_bh(&mhi_cntrl->pm_lock); /* do a quick check to see if any pending votes to keep us busy */ if (atomic_read(&mhi_cntrl->pending_pkts)) { if (atomic_read(&mhi_cntrl->pending_pkts) || atomic_read(&mhi_dev->bus_vote)) { MHI_VERB("Busy, aborting M3\n"); return -EBUSY; } Loading @@ -1256,7 +1261,8 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) * Check the votes once more to see if we should abort * suspend. */ if (atomic_read(&mhi_cntrl->pending_pkts)) { if (atomic_read(&mhi_cntrl->pending_pkts) || atomic_read(&mhi_dev->bus_vote)) { MHI_VERB("Busy, aborting M3\n"); ret = -EBUSY; goto error_suspend; Loading Loading
drivers/bus/mhi/core/mhi_init.c +4 −1 Original line number Diff line number Diff line Loading @@ -348,6 +348,9 @@ void mhi_destroy_sysfs(struct mhi_controller *mhi_cntrl) } spin_unlock(&mhi_tsync->lock); if (mhi_tsync->db_response_pending) complete(&mhi_tsync->db_completion); kfree(mhi_cntrl->mhi_tsync); mhi_cntrl->mhi_tsync = NULL; mutex_unlock(&mhi_cntrl->tsync_mutex); Loading Loading @@ -1234,7 +1237,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, mhi_event->process_event = mhi_process_ctrl_ev_ring; break; case MHI_ER_TSYNC_ELEMENT_TYPE: mhi_event->process_event = mhi_process_tsync_event_ring; mhi_event->process_event = mhi_process_tsync_ev_ring; break; case MHI_ER_BW_SCALE_ELEMENT_TYPE: mhi_event->process_event = mhi_process_bw_scale_ev_ring; Loading
drivers/bus/mhi/core/mhi_internal.h +6 −4 Original line number Diff line number Diff line Loading @@ -716,8 +716,6 @@ struct mhi_chan { struct tsync_node { struct list_head node; u32 sequence; u32 int_sequence; u64 local_time; u64 remote_time; struct mhi_device *mhi_dev; void (*cb_func)(struct mhi_device *mhi_dev, u32 sequence, Loading @@ -727,7 +725,11 @@ struct tsync_node { struct mhi_timesync { void __iomem *time_reg; u32 int_sequence; u64 local_time; u64 remote_time; bool db_support; bool db_response_pending; struct completion db_completion; spinlock_t lock; /* list protection */ struct list_head head; }; Loading Loading @@ -786,7 +788,7 @@ 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, struct mhi_event *mhi_event, u32 event_quota); int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl, 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); Loading
drivers/bus/mhi/core/mhi_main.c +133 −87 Original line number Diff line number Diff line Loading @@ -1348,42 +1348,69 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, return count; } int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl, int mhi_process_tsync_ev_ring(struct mhi_controller *mhi_cntrl, struct mhi_event *mhi_event, u32 event_quota) { struct mhi_tre *dev_rp, *local_rp; struct mhi_tre *dev_rp; struct mhi_ring *ev_ring = &mhi_event->ring; struct mhi_event_ctxt *er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; int count = 0; u32 int_sequence, unit; u32 sequence; u64 remote_time; int ret = 0; if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) { MHI_LOG("No EV access, PM_STATE:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state)); return -EIO; spin_lock_bh(&mhi_event->lock); dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); if (ev_ring->rp == dev_rp) { spin_unlock_bh(&mhi_event->lock); goto exit_tsync_process; } dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); local_rp = ev_ring->rp; /* if rp points to base, we need to wrap it around */ if (dev_rp == ev_ring->base) dev_rp = ev_ring->base + ev_ring->len; dev_rp--; while (dev_rp != local_rp) { enum MHI_PKT_TYPE type = MHI_TRE_GET_EV_TYPE(local_rp); struct tsync_node *tsync_node; /* fast forward to currently processed element and recycle er */ ev_ring->rp = dev_rp; ev_ring->wp = dev_rp - 1; if (ev_ring->wp < ev_ring->base) ev_ring->wp = ev_ring->base + ev_ring->len - ev_ring->el_size; mhi_recycle_fwd_ev_ring_element(mhi_cntrl, ev_ring); MHI_VERB("Processing Event:0x%llx 0x%08x 0x%08x\n", local_rp->ptr, local_rp->dword[0], local_rp->dword[1]); MHI_ASSERT(MHI_TRE_GET_EV_TYPE(dev_rp) != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event"); MHI_ASSERT(type != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event"); sequence = MHI_TRE_GET_EV_TSYNC_SEQ(dev_rp); remote_time = MHI_TRE_GET_EV_TIME(dev_rp); int_sequence = MHI_TRE_GET_EV_TSYNC_SEQ(local_rp); unit = MHI_TRE_GET_EV_TSYNC_UNIT(local_rp); remote_time = MHI_TRE_GET_EV_TIME(local_rp); MHI_VERB("Received TSYNC event with seq:0x%llx time:0x%llx\n", sequence, remote_time); read_lock_bh(&mhi_cntrl->pm_lock); if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) mhi_ring_er_db(mhi_event); read_unlock_bh(&mhi_cntrl->pm_lock); spin_unlock_bh(&mhi_event->lock); mutex_lock(&mhi_cntrl->tsync_mutex); if (unlikely(mhi_tsync->int_sequence != sequence)) { MHI_ASSERT(1, "Unexpected response:0x%llx Expected:0x%llx\n", sequence, mhi_tsync->int_sequence); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); mutex_unlock(&mhi_cntrl->tsync_mutex); goto exit_tsync_process; } do { struct tsync_node *tsync_node; spin_lock(&mhi_tsync->lock); tsync_node = list_first_entry_or_null(&mhi_tsync->head, struct tsync_node, node); Loading @@ -1395,35 +1422,24 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl, list_del(&tsync_node->node); spin_unlock(&mhi_tsync->lock); /* * device may not able to process all time sync commands * host issue and only process last command it receive */ if (tsync_node->int_sequence == int_sequence) { tsync_node->cb_func(tsync_node->mhi_dev, tsync_node->sequence, tsync_node->local_time, remote_time); kfree(tsync_node); } else { mhi_tsync->local_time, remote_time); kfree(tsync_node); } } while (true); mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp = ev_ring->rp; dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); count++; } mhi_tsync->db_response_pending = false; mhi_tsync->remote_time = remote_time; complete(&mhi_tsync->db_completion); read_lock_bh(&mhi_cntrl->pm_lock); if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) mhi_ring_er_db(mhi_event); read_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); mutex_unlock(&mhi_cntrl->tsync_mutex); exit_tsync_process: MHI_VERB("exit er_index:%u\n", mhi_event->er_index); return count; return ret; } int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, Loading Loading @@ -1475,13 +1491,10 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, read_unlock_bh(&mhi_cntrl->pm_lock); spin_unlock_bh(&mhi_event->lock); atomic_inc(&mhi_cntrl->pending_pkts); ret = mhi_device_get_sync(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); if (ret) { atomic_dec(&mhi_cntrl->pending_pkts); if (ret) goto exit_bw_scale_process; } mutex_lock(&mhi_cntrl->pm_mutex); Loading @@ -1499,7 +1512,6 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, read_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); atomic_dec(&mhi_cntrl->pending_pkts); mutex_unlock(&mhi_cntrl->pm_mutex); Loading Loading @@ -2466,13 +2478,37 @@ int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; u64 local_time; int ret; mutex_lock(&mhi_cntrl->tsync_mutex); /* not all devices support time features */ if (!mhi_tsync) { ret = -EIO; goto error_unlock; if (!mhi_tsync) return -EINVAL; if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) { MHI_ERR("MHI is not in active state, pm_state:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state)); return -EIO; } mutex_lock(&mhi_cntrl->tsync_mutex); /* return times from last async request completion */ if (mhi_tsync->db_response_pending) { local_time = mhi_tsync->local_time; mutex_unlock(&mhi_cntrl->tsync_mutex); ret = wait_for_completion_timeout(&mhi_tsync->db_completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || !ret) { MHI_ERR("Pending DB request did not complete, abort\n"); return -EAGAIN; } *t_host = local_time; *t_dev = mhi_tsync->remote_time; return 0; } /* bring to M0 state */ Loading Loading @@ -2542,17 +2578,16 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_timesync *mhi_tsync = mhi_cntrl->mhi_tsync; struct tsync_node *tsync_node; int ret; int ret = 0; /* not all devices support all time features */ if (!mhi_tsync || !mhi_tsync->db_support) return -EINVAL; mutex_lock(&mhi_cntrl->tsync_mutex); if (!mhi_tsync || !mhi_tsync->db_support) { ret = -EIO; goto error_unlock; } /* tsync db can only be rung in M0 state */ ret = __mhi_device_get_sync(mhi_cntrl); ret = mhi_device_get_sync(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); if (ret) goto error_unlock; Loading @@ -2566,6 +2601,10 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, } read_unlock_bh(&mhi_cntrl->pm_lock); MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state), TO_MHI_STATE_STR(mhi_cntrl->dev_state)); /* * technically we can use GFP_KERNEL, but wants to avoid * # of times scheduling out Loading @@ -2576,15 +2615,17 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, goto error_no_mem; } mhi_tsync->int_sequence++; if (mhi_tsync->int_sequence == 0xFFFFFFFF) mhi_tsync->int_sequence = 0; tsync_node->sequence = sequence; tsync_node->int_sequence = mhi_tsync->int_sequence; tsync_node->cb_func = cb_func; tsync_node->mhi_dev = mhi_dev; if (mhi_tsync->db_response_pending) goto skip_tsync_db; mhi_tsync->int_sequence++; if (mhi_tsync->int_sequence == 0xFFFFFFFF) mhi_tsync->int_sequence = 0; /* disable link level low power modes */ ret = mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data); if (ret) { Loading @@ -2593,10 +2634,6 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, goto error_invalid_state; } spin_lock(&mhi_tsync->lock); list_add_tail(&tsync_node->node, &mhi_tsync->head); spin_unlock(&mhi_tsync->lock); /* * time critical code, delay between these two steps should be * deterministic as possible. Loading @@ -2604,9 +2641,9 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, preempt_disable(); local_irq_disable(); tsync_node->local_time = mhi_tsync->local_time = mhi_cntrl->time_get(mhi_cntrl, mhi_cntrl->priv_data); writel_relaxed_no_log(tsync_node->int_sequence, mhi_cntrl->tsync_db); writel_relaxed_no_log(mhi_tsync->int_sequence, mhi_cntrl->tsync_db); /* write must go thru immediately */ wmb(); Loading @@ -2615,15 +2652,24 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, mhi_cntrl->lpm_enable(mhi_cntrl, mhi_cntrl->priv_data); ret = 0; MHI_VERB("time DB request with seq:0x%llx\n", mhi_tsync->int_sequence); mhi_tsync->db_response_pending = true; init_completion(&mhi_tsync->db_completion); skip_tsync_db: spin_lock(&mhi_tsync->lock); list_add_tail(&tsync_node->node, &mhi_tsync->head); spin_unlock(&mhi_tsync->lock); mutex_unlock(&mhi_cntrl->tsync_mutex); return 0; error_invalid_state: if (ret) kfree(tsync_node); error_no_mem: read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); mhi_device_put(mhi_cntrl->mhi_dev, MHI_VOTE_DEVICE | MHI_VOTE_BUS); error_unlock: mutex_unlock(&mhi_cntrl->tsync_mutex); return ret; Loading
drivers/bus/mhi/core/mhi_pm.c +8 −2 Original line number Diff line number Diff line Loading @@ -823,6 +823,9 @@ void mhi_special_purpose_work(struct work_struct *work) TO_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; /* 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 @@ -1223,6 +1226,7 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) int ret; enum MHI_PM_STATE new_state; struct mhi_chan *itr, *tmp; struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev; read_lock_bh(&mhi_cntrl->pm_lock); if (mhi_cntrl->pm_state == MHI_PM_DISABLE) { Loading @@ -1237,7 +1241,8 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) read_unlock_bh(&mhi_cntrl->pm_lock); /* do a quick check to see if any pending votes to keep us busy */ if (atomic_read(&mhi_cntrl->pending_pkts)) { if (atomic_read(&mhi_cntrl->pending_pkts) || atomic_read(&mhi_dev->bus_vote)) { MHI_VERB("Busy, aborting M3\n"); return -EBUSY; } Loading @@ -1256,7 +1261,8 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client) * Check the votes once more to see if we should abort * suspend. */ if (atomic_read(&mhi_cntrl->pending_pkts)) { if (atomic_read(&mhi_cntrl->pending_pkts) || atomic_read(&mhi_dev->bus_vote)) { MHI_VERB("Busy, aborting M3\n"); ret = -EBUSY; goto error_suspend; Loading