Loading drivers/bus/mhi/controllers/mhi_arch_qcom.c +107 −26 Original line number Diff line number Diff line Loading @@ -82,7 +82,8 @@ static void mhi_arch_pci_link_state_cb(struct msm_pcie_notify *notify) struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct pci_dev *pci_dev = mhi_dev->pci_dev; if (notify->event == MSM_PCIE_EVENT_WAKEUP) { switch (notify->event) { case MSM_PCIE_EVENT_WAKEUP: MHI_LOG("Received MSM_PCIE_EVENT_WAKE signal\n"); /* bring link out of d3cold */ Loading @@ -90,6 +91,15 @@ static void mhi_arch_pci_link_state_cb(struct msm_pcie_notify *notify) pm_runtime_get(&pci_dev->dev); pm_runtime_put_noidle(&pci_dev->dev); } break; case MSM_PCIE_EVENT_L1SS_TIMEOUT: MHI_VERB("Received MSM_PCIE_EVENT_L1SS_TIMEOUT signal\n"); pm_runtime_mark_last_busy(&pci_dev->dev); pm_request_autosuspend(&pci_dev->dev); break; default: MHI_ERR("Unhandled event 0x%x\n", notify->event); } } Loading Loading @@ -133,6 +143,22 @@ static int mhi_arch_esoc_ops_power_on(void *priv, unsigned int flags) return mhi_pci_probe(pci_dev, NULL); } static void mhi_arch_link_off(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct pci_dev *pci_dev = mhi_dev->pci_dev; MHI_LOG("Entered\n"); pci_set_power_state(pci_dev, PCI_D3hot); /* release the resources */ msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); mhi_arch_set_bus_request(mhi_cntrl, 0); MHI_LOG("Exited\n"); } static void mhi_arch_esoc_ops_power_off(void *priv, unsigned int flags) { struct mhi_controller *mhi_cntrl = priv; Loading @@ -156,7 +182,7 @@ static void mhi_arch_esoc_ops_power_off(void *priv, unsigned int flags) /* turn the link off */ mhi_deinit_pci_dev(mhi_cntrl); mhi_arch_link_off(mhi_cntrl, false); mhi_arch_link_off(mhi_cntrl); /* wait for boot monitor to exit */ async_synchronize_cookie(arch_info->cookie + 1); Loading Loading @@ -213,9 +239,16 @@ static void mhi_boot_monitor(void *data, async_cookie_t cookie) TO_MHI_EXEC_STR(mhi_cntrl->ee)); /* if we successfully booted to amss disable boot log channel */ if (mhi_cntrl->ee == MHI_EE_AMSS) { boot_dev = arch_info->boot_dev; if (boot_dev && mhi_cntrl->ee == MHI_EE_AMSS) if (boot_dev) mhi_unprepare_from_transfer(boot_dev); /* enable link inactivity timer to start auto suspend */ msm_pcie_l1ss_timeout_enable(mhi_dev->pci_dev); pm_runtime_allow(&mhi_dev->pci_dev->dev); } } int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) Loading Loading @@ -265,8 +298,7 @@ static void mhi_arch_pcie_bw_scale_work(struct work_struct *work) int ret; mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on || pm_runtime_status_suspended(dev) || dev->power.is_suspended) if (!mhi_dev->powered_on || MHI_IS_SUSPENDED(mhi_dev->suspend_mode)) goto exit_work; /* copy the latest speed change */ Loading Loading @@ -353,6 +385,7 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) return -ENOMEM; mhi_dev->arch_info = arch_info; arch_info->mhi_dev = mhi_dev; snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u", mhi_cntrl->dev_id, mhi_cntrl->domain, mhi_cntrl->bus, Loading @@ -374,7 +407,9 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* register with pcie rc for WAKE# events */ reg_event = &arch_info->pcie_reg_event; reg_event->events = MSM_PCIE_EVENT_WAKEUP; reg_event->events = MSM_PCIE_EVENT_WAKEUP | MSM_PCIE_EVENT_L1SS_TIMEOUT; reg_event->user = mhi_dev->pci_dev; reg_event->callback = mhi_arch_pci_link_state_cb; reg_event->notify.data = mhi_cntrl; Loading Loading @@ -407,6 +442,13 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* save reference state for pcie config space */ arch_info->ref_pcie_state = pci_store_saved_state( mhi_dev->pci_dev); /* * MHI host driver has full autonomy to manage power state. * Disable all automatic power collapse features */ msm_pcie_pm_control(MSM_PCIE_DISABLE_PC, mhi_cntrl->bus, mhi_dev->pci_dev, NULL, 0); mhi_dev->pci_dev->no_d3hot = true; INIT_WORK(&arch_info->bw_scale_work, mhi_arch_pcie_bw_scale_work); Loading Loading @@ -566,50 +608,58 @@ void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl) mhi_cntrl->dev = NULL; } int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful) int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; int ret; int ret = 0; MHI_LOG("Entered\n"); if (graceful) { /* disable inactivity timer */ msm_pcie_l1ss_timeout_disable(pci_dev); switch (mhi_dev->suspend_mode) { case MHI_DEFAULT_SUSPEND: pci_clear_master(pci_dev); ret = pci_save_state(mhi_dev->pci_dev); if (ret) { MHI_ERR("Failed with pci_save_state, ret:%d\n", ret); return ret; goto exit_suspend; } arch_info->pcie_state = pci_store_saved_state(pci_dev); pci_disable_device(pci_dev); } /* * We will always attempt to put link into D3hot, however * link down may have happened due to error fatal, so * ignoring the return code */ pci_set_power_state(pci_dev, PCI_D3hot); /* release the resources */ msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); mhi_arch_set_bus_request(mhi_cntrl, 0); break; case MHI_FAST_LINK_OFF: case MHI_ACTIVE_STATE: case MHI_FAST_LINK_ON:/* keeping link on do nothing */ break; } MHI_LOG("Exited\n"); exit_suspend: if (ret) msm_pcie_l1ss_timeout_enable(pci_dev); return 0; MHI_LOG("Exited with ret:%d\n", ret); return ret; } int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) static int __mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; struct mhi_link_info *cur_info = &arch_info->current_link_info; struct mhi_link_info *updated_info = &mhi_cntrl->mhi_link_info; int ret; MHI_LOG("Entered\n"); Loading Loading @@ -647,6 +697,35 @@ int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) pci_restore_state(pci_dev); pci_set_master(pci_dev); return 0; } int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; struct mhi_link_info *cur_info = &arch_info->current_link_info; struct mhi_link_info *updated_info = &mhi_cntrl->mhi_link_info; int ret = 0; MHI_LOG("Entered\n"); switch (mhi_dev->suspend_mode) { case MHI_DEFAULT_SUSPEND: ret = __mhi_arch_link_resume(mhi_cntrl); break; case MHI_FAST_LINK_OFF: case MHI_ACTIVE_STATE: case MHI_FAST_LINK_ON: break; } if (ret) { MHI_ERR("Link training failed, ret:%d\n", ret); return ret; } /* BW request from device doesn't match current link speed */ if (cur_info->target_link_speed != updated_info->target_link_speed || cur_info->target_link_width != updated_info->target_link_width) { Loading @@ -655,6 +734,8 @@ int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) *cur_info = *updated_info; } msm_pcie_l1ss_timeout_enable(pci_dev); MHI_LOG("Exited\n"); return 0; Loading drivers/bus/mhi/controllers/mhi_qcom.c +108 −27 Original line number Diff line number Diff line Loading @@ -195,7 +195,43 @@ static int mhi_init_pci_dev(struct mhi_controller *mhi_cntrl) static int mhi_runtime_suspend(struct device *dev) { return -EBUSY; int ret = 0; struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); MHI_LOG("Enter\n"); mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on) { MHI_LOG("Not fully powered, return success\n"); mutex_unlock(&mhi_cntrl->pm_mutex); return 0; } ret = mhi_pm_suspend(mhi_cntrl); if (ret) { MHI_LOG("Abort due to ret:%d\n", ret); goto exit_runtime_suspend; } mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; ret = mhi_arch_link_suspend(mhi_cntrl); /* failed suspending link abort mhi suspend */ if (ret) { MHI_LOG("Failed to suspend link, abort suspend\n"); mhi_pm_resume(mhi_cntrl); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; } exit_runtime_suspend: mutex_unlock(&mhi_cntrl->pm_mutex); MHI_LOG("Exited with ret:%d\n", ret); return ret; } static int mhi_runtime_idle(struct device *dev) Loading Loading @@ -236,12 +272,18 @@ static int mhi_runtime_resume(struct device *dev) } /* turn on link */ ret = mhi_arch_link_on(mhi_cntrl); ret = mhi_arch_link_resume(mhi_cntrl); if (ret) goto rpm_resume_exit; /* enter M0 state */ /* transition to M0 state */ if (mhi_dev->suspend_mode == MHI_DEFAULT_SUSPEND) ret = mhi_pm_resume(mhi_cntrl); else ret = mhi_pm_fast_resume(mhi_cntrl, MHI_FAST_LINK_ON); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; rpm_resume_exit: mutex_unlock(&mhi_cntrl->pm_mutex); Loading @@ -252,41 +294,81 @@ static int mhi_runtime_resume(struct device *dev) static int mhi_system_resume(struct device *dev) { int ret = 0; struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); ret = mhi_runtime_resume(dev); if (ret) { MHI_ERR("Failed to resume link\n"); } else { pm_runtime_set_active(dev); pm_runtime_enable(dev); } return ret; return mhi_runtime_resume(dev); } int mhi_system_suspend(struct device *dev) { struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); int ret; MHI_LOG("Entered\n"); /* if rpm status still active then force suspend */ if (!pm_runtime_status_suspended(dev)) { ret = mhi_runtime_suspend(dev); mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on) { MHI_LOG("Not fully powered, return success\n"); mutex_unlock(&mhi_cntrl->pm_mutex); return 0; } /* * pci framework always makes a dummy vote to rpm * framework to resume before calling system suspend * hence usage count is minimum one */ if (atomic_read(&dev->power.usage_count) > 1) { /* * clients have requested to keep link on, try * fast suspend. No need to notify clients since * we will not be turning off the pcie link */ ret = mhi_pm_fast_suspend(mhi_cntrl, false); mhi_dev->suspend_mode = MHI_FAST_LINK_ON; } else { /* try normal suspend */ mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; ret = mhi_pm_suspend(mhi_cntrl); /* * normal suspend failed because we're busy, try * fast suspend before aborting system suspend. * this could happens if client has disabled * device lpm but no active vote for PCIe from * apps processor */ if (ret == -EBUSY) { ret = mhi_pm_fast_suspend(mhi_cntrl, true); mhi_dev->suspend_mode = MHI_FAST_LINK_ON; } } if (ret) { MHI_LOG("suspend failed ret:%d\n", ret); return ret; MHI_LOG("Abort due to ret:%d\n", ret); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; goto exit_system_suspend; } ret = mhi_arch_link_suspend(mhi_cntrl); /* failed suspending link abort mhi suspend */ if (ret) { MHI_LOG("Failed to suspend link, abort suspend\n"); if (mhi_dev->suspend_mode == MHI_DEFAULT_SUSPEND) mhi_pm_resume(mhi_cntrl); else mhi_pm_fast_resume(mhi_cntrl, MHI_FAST_LINK_OFF); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; } pm_runtime_set_suspended(dev); pm_runtime_disable(dev); exit_system_suspend: mutex_unlock(&mhi_cntrl->pm_mutex); MHI_LOG("Exit\n"); return 0; MHI_LOG("Exit with ret:%d\n", ret); return ret; } /* checks if link is down */ Loading Loading @@ -658,7 +740,6 @@ int mhi_pci_probe(struct pci_dev *pci_dev, } pm_runtime_mark_last_busy(&pci_dev->dev); pm_runtime_allow(&pci_dev->dev); MHI_LOG("Return successful\n"); Loading drivers/bus/mhi/controllers/mhi_qcom.h +15 −5 Original line number Diff line number Diff line Loading @@ -29,8 +29,18 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define TO_MHI_EXEC_STR(ee) (ee >= MHI_EE_MAX ? "INVALID_EE" : mhi_ee_str[ee]) enum mhi_suspend_mode { MHI_ACTIVE_STATE, MHI_DEFAULT_SUSPEND, MHI_FAST_LINK_OFF, MHI_FAST_LINK_ON, }; #define MHI_IS_SUSPENDED(mode) (mode) struct mhi_dev { struct pci_dev *pci_dev; bool drv_supported; u32 smmu_cfg; int resn; void *arch_info; Loading @@ -38,6 +48,7 @@ struct mhi_dev { dma_addr_t iova_start; dma_addr_t iova_stop; bool lpm_disabled; enum mhi_suspend_mode suspend_mode; /* if set, soc support dynamic bw scaling */ void (*bw_scale)(struct mhi_controller *mhi_cntrl, Loading @@ -55,8 +66,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl); void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl); int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl); void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl); int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful); int mhi_arch_link_on(struct mhi_controller *mhi_cntrl); int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl); int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl); #else Loading @@ -82,13 +93,12 @@ static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl) { } static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful) static inline int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl) { return 0; } static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) static inline int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { return 0; } Loading Loading
drivers/bus/mhi/controllers/mhi_arch_qcom.c +107 −26 Original line number Diff line number Diff line Loading @@ -82,7 +82,8 @@ static void mhi_arch_pci_link_state_cb(struct msm_pcie_notify *notify) struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct pci_dev *pci_dev = mhi_dev->pci_dev; if (notify->event == MSM_PCIE_EVENT_WAKEUP) { switch (notify->event) { case MSM_PCIE_EVENT_WAKEUP: MHI_LOG("Received MSM_PCIE_EVENT_WAKE signal\n"); /* bring link out of d3cold */ Loading @@ -90,6 +91,15 @@ static void mhi_arch_pci_link_state_cb(struct msm_pcie_notify *notify) pm_runtime_get(&pci_dev->dev); pm_runtime_put_noidle(&pci_dev->dev); } break; case MSM_PCIE_EVENT_L1SS_TIMEOUT: MHI_VERB("Received MSM_PCIE_EVENT_L1SS_TIMEOUT signal\n"); pm_runtime_mark_last_busy(&pci_dev->dev); pm_request_autosuspend(&pci_dev->dev); break; default: MHI_ERR("Unhandled event 0x%x\n", notify->event); } } Loading Loading @@ -133,6 +143,22 @@ static int mhi_arch_esoc_ops_power_on(void *priv, unsigned int flags) return mhi_pci_probe(pci_dev, NULL); } static void mhi_arch_link_off(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct pci_dev *pci_dev = mhi_dev->pci_dev; MHI_LOG("Entered\n"); pci_set_power_state(pci_dev, PCI_D3hot); /* release the resources */ msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); mhi_arch_set_bus_request(mhi_cntrl, 0); MHI_LOG("Exited\n"); } static void mhi_arch_esoc_ops_power_off(void *priv, unsigned int flags) { struct mhi_controller *mhi_cntrl = priv; Loading @@ -156,7 +182,7 @@ static void mhi_arch_esoc_ops_power_off(void *priv, unsigned int flags) /* turn the link off */ mhi_deinit_pci_dev(mhi_cntrl); mhi_arch_link_off(mhi_cntrl, false); mhi_arch_link_off(mhi_cntrl); /* wait for boot monitor to exit */ async_synchronize_cookie(arch_info->cookie + 1); Loading Loading @@ -213,9 +239,16 @@ static void mhi_boot_monitor(void *data, async_cookie_t cookie) TO_MHI_EXEC_STR(mhi_cntrl->ee)); /* if we successfully booted to amss disable boot log channel */ if (mhi_cntrl->ee == MHI_EE_AMSS) { boot_dev = arch_info->boot_dev; if (boot_dev && mhi_cntrl->ee == MHI_EE_AMSS) if (boot_dev) mhi_unprepare_from_transfer(boot_dev); /* enable link inactivity timer to start auto suspend */ msm_pcie_l1ss_timeout_enable(mhi_dev->pci_dev); pm_runtime_allow(&mhi_dev->pci_dev->dev); } } int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) Loading Loading @@ -265,8 +298,7 @@ static void mhi_arch_pcie_bw_scale_work(struct work_struct *work) int ret; mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on || pm_runtime_status_suspended(dev) || dev->power.is_suspended) if (!mhi_dev->powered_on || MHI_IS_SUSPENDED(mhi_dev->suspend_mode)) goto exit_work; /* copy the latest speed change */ Loading Loading @@ -353,6 +385,7 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) return -ENOMEM; mhi_dev->arch_info = arch_info; arch_info->mhi_dev = mhi_dev; snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u", mhi_cntrl->dev_id, mhi_cntrl->domain, mhi_cntrl->bus, Loading @@ -374,7 +407,9 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* register with pcie rc for WAKE# events */ reg_event = &arch_info->pcie_reg_event; reg_event->events = MSM_PCIE_EVENT_WAKEUP; reg_event->events = MSM_PCIE_EVENT_WAKEUP | MSM_PCIE_EVENT_L1SS_TIMEOUT; reg_event->user = mhi_dev->pci_dev; reg_event->callback = mhi_arch_pci_link_state_cb; reg_event->notify.data = mhi_cntrl; Loading Loading @@ -407,6 +442,13 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* save reference state for pcie config space */ arch_info->ref_pcie_state = pci_store_saved_state( mhi_dev->pci_dev); /* * MHI host driver has full autonomy to manage power state. * Disable all automatic power collapse features */ msm_pcie_pm_control(MSM_PCIE_DISABLE_PC, mhi_cntrl->bus, mhi_dev->pci_dev, NULL, 0); mhi_dev->pci_dev->no_d3hot = true; INIT_WORK(&arch_info->bw_scale_work, mhi_arch_pcie_bw_scale_work); Loading Loading @@ -566,50 +608,58 @@ void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl) mhi_cntrl->dev = NULL; } int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful) int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; int ret; int ret = 0; MHI_LOG("Entered\n"); if (graceful) { /* disable inactivity timer */ msm_pcie_l1ss_timeout_disable(pci_dev); switch (mhi_dev->suspend_mode) { case MHI_DEFAULT_SUSPEND: pci_clear_master(pci_dev); ret = pci_save_state(mhi_dev->pci_dev); if (ret) { MHI_ERR("Failed with pci_save_state, ret:%d\n", ret); return ret; goto exit_suspend; } arch_info->pcie_state = pci_store_saved_state(pci_dev); pci_disable_device(pci_dev); } /* * We will always attempt to put link into D3hot, however * link down may have happened due to error fatal, so * ignoring the return code */ pci_set_power_state(pci_dev, PCI_D3hot); /* release the resources */ msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); msm_pcie_pm_control(MSM_PCIE_SUSPEND, mhi_cntrl->bus, pci_dev, NULL, 0); mhi_arch_set_bus_request(mhi_cntrl, 0); break; case MHI_FAST_LINK_OFF: case MHI_ACTIVE_STATE: case MHI_FAST_LINK_ON:/* keeping link on do nothing */ break; } MHI_LOG("Exited\n"); exit_suspend: if (ret) msm_pcie_l1ss_timeout_enable(pci_dev); return 0; MHI_LOG("Exited with ret:%d\n", ret); return ret; } int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) static int __mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; struct mhi_link_info *cur_info = &arch_info->current_link_info; struct mhi_link_info *updated_info = &mhi_cntrl->mhi_link_info; int ret; MHI_LOG("Entered\n"); Loading Loading @@ -647,6 +697,35 @@ int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) pci_restore_state(pci_dev); pci_set_master(pci_dev); return 0; } int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; struct pci_dev *pci_dev = mhi_dev->pci_dev; struct mhi_link_info *cur_info = &arch_info->current_link_info; struct mhi_link_info *updated_info = &mhi_cntrl->mhi_link_info; int ret = 0; MHI_LOG("Entered\n"); switch (mhi_dev->suspend_mode) { case MHI_DEFAULT_SUSPEND: ret = __mhi_arch_link_resume(mhi_cntrl); break; case MHI_FAST_LINK_OFF: case MHI_ACTIVE_STATE: case MHI_FAST_LINK_ON: break; } if (ret) { MHI_ERR("Link training failed, ret:%d\n", ret); return ret; } /* BW request from device doesn't match current link speed */ if (cur_info->target_link_speed != updated_info->target_link_speed || cur_info->target_link_width != updated_info->target_link_width) { Loading @@ -655,6 +734,8 @@ int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) *cur_info = *updated_info; } msm_pcie_l1ss_timeout_enable(pci_dev); MHI_LOG("Exited\n"); return 0; Loading
drivers/bus/mhi/controllers/mhi_qcom.c +108 −27 Original line number Diff line number Diff line Loading @@ -195,7 +195,43 @@ static int mhi_init_pci_dev(struct mhi_controller *mhi_cntrl) static int mhi_runtime_suspend(struct device *dev) { return -EBUSY; int ret = 0; struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); MHI_LOG("Enter\n"); mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on) { MHI_LOG("Not fully powered, return success\n"); mutex_unlock(&mhi_cntrl->pm_mutex); return 0; } ret = mhi_pm_suspend(mhi_cntrl); if (ret) { MHI_LOG("Abort due to ret:%d\n", ret); goto exit_runtime_suspend; } mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; ret = mhi_arch_link_suspend(mhi_cntrl); /* failed suspending link abort mhi suspend */ if (ret) { MHI_LOG("Failed to suspend link, abort suspend\n"); mhi_pm_resume(mhi_cntrl); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; } exit_runtime_suspend: mutex_unlock(&mhi_cntrl->pm_mutex); MHI_LOG("Exited with ret:%d\n", ret); return ret; } static int mhi_runtime_idle(struct device *dev) Loading Loading @@ -236,12 +272,18 @@ static int mhi_runtime_resume(struct device *dev) } /* turn on link */ ret = mhi_arch_link_on(mhi_cntrl); ret = mhi_arch_link_resume(mhi_cntrl); if (ret) goto rpm_resume_exit; /* enter M0 state */ /* transition to M0 state */ if (mhi_dev->suspend_mode == MHI_DEFAULT_SUSPEND) ret = mhi_pm_resume(mhi_cntrl); else ret = mhi_pm_fast_resume(mhi_cntrl, MHI_FAST_LINK_ON); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; rpm_resume_exit: mutex_unlock(&mhi_cntrl->pm_mutex); Loading @@ -252,41 +294,81 @@ static int mhi_runtime_resume(struct device *dev) static int mhi_system_resume(struct device *dev) { int ret = 0; struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); ret = mhi_runtime_resume(dev); if (ret) { MHI_ERR("Failed to resume link\n"); } else { pm_runtime_set_active(dev); pm_runtime_enable(dev); } return ret; return mhi_runtime_resume(dev); } int mhi_system_suspend(struct device *dev) { struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); int ret; MHI_LOG("Entered\n"); /* if rpm status still active then force suspend */ if (!pm_runtime_status_suspended(dev)) { ret = mhi_runtime_suspend(dev); mutex_lock(&mhi_cntrl->pm_mutex); if (!mhi_dev->powered_on) { MHI_LOG("Not fully powered, return success\n"); mutex_unlock(&mhi_cntrl->pm_mutex); return 0; } /* * pci framework always makes a dummy vote to rpm * framework to resume before calling system suspend * hence usage count is minimum one */ if (atomic_read(&dev->power.usage_count) > 1) { /* * clients have requested to keep link on, try * fast suspend. No need to notify clients since * we will not be turning off the pcie link */ ret = mhi_pm_fast_suspend(mhi_cntrl, false); mhi_dev->suspend_mode = MHI_FAST_LINK_ON; } else { /* try normal suspend */ mhi_dev->suspend_mode = MHI_DEFAULT_SUSPEND; ret = mhi_pm_suspend(mhi_cntrl); /* * normal suspend failed because we're busy, try * fast suspend before aborting system suspend. * this could happens if client has disabled * device lpm but no active vote for PCIe from * apps processor */ if (ret == -EBUSY) { ret = mhi_pm_fast_suspend(mhi_cntrl, true); mhi_dev->suspend_mode = MHI_FAST_LINK_ON; } } if (ret) { MHI_LOG("suspend failed ret:%d\n", ret); return ret; MHI_LOG("Abort due to ret:%d\n", ret); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; goto exit_system_suspend; } ret = mhi_arch_link_suspend(mhi_cntrl); /* failed suspending link abort mhi suspend */ if (ret) { MHI_LOG("Failed to suspend link, abort suspend\n"); if (mhi_dev->suspend_mode == MHI_DEFAULT_SUSPEND) mhi_pm_resume(mhi_cntrl); else mhi_pm_fast_resume(mhi_cntrl, MHI_FAST_LINK_OFF); mhi_dev->suspend_mode = MHI_ACTIVE_STATE; } pm_runtime_set_suspended(dev); pm_runtime_disable(dev); exit_system_suspend: mutex_unlock(&mhi_cntrl->pm_mutex); MHI_LOG("Exit\n"); return 0; MHI_LOG("Exit with ret:%d\n", ret); return ret; } /* checks if link is down */ Loading Loading @@ -658,7 +740,6 @@ int mhi_pci_probe(struct pci_dev *pci_dev, } pm_runtime_mark_last_busy(&pci_dev->dev); pm_runtime_allow(&pci_dev->dev); MHI_LOG("Return successful\n"); Loading
drivers/bus/mhi/controllers/mhi_qcom.h +15 −5 Original line number Diff line number Diff line Loading @@ -29,8 +29,18 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define TO_MHI_EXEC_STR(ee) (ee >= MHI_EE_MAX ? "INVALID_EE" : mhi_ee_str[ee]) enum mhi_suspend_mode { MHI_ACTIVE_STATE, MHI_DEFAULT_SUSPEND, MHI_FAST_LINK_OFF, MHI_FAST_LINK_ON, }; #define MHI_IS_SUSPENDED(mode) (mode) struct mhi_dev { struct pci_dev *pci_dev; bool drv_supported; u32 smmu_cfg; int resn; void *arch_info; Loading @@ -38,6 +48,7 @@ struct mhi_dev { dma_addr_t iova_start; dma_addr_t iova_stop; bool lpm_disabled; enum mhi_suspend_mode suspend_mode; /* if set, soc support dynamic bw scaling */ void (*bw_scale)(struct mhi_controller *mhi_cntrl, Loading @@ -55,8 +66,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl); void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl); int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl); void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl); int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful); int mhi_arch_link_on(struct mhi_controller *mhi_cntrl); int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl); int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl); #else Loading @@ -82,13 +93,12 @@ static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl) { } static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl, bool graceful) static inline int mhi_arch_link_suspend(struct mhi_controller *mhi_cntrl) { return 0; } static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl) static inline int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl) { return 0; } Loading