Loading drivers/platform/msm/mhi_dev/mhi.c +259 −20 Original line number Diff line number Diff line Loading @@ -37,8 +37,8 @@ /* Wait time on the device for Host to set M0 state */ #define MHI_DEV_M0_MAX_CNT 30 /* Wait time before suspend/resume is complete */ #define MHI_SUSPEND_MIN 10000 #define MHI_SUSPEND_TIMEOUT 3000 #define MHI_SUSPEND_MIN 100 #define MHI_SUSPEND_TIMEOUT 600 #define MHI_MASK_CH_EV_LEN 32 #define MHI_RING_CMD_ID 0 #define MHI_RING_PRIMARY_EVT_ID 1 Loading @@ -58,6 +58,8 @@ #define MHI_IPC_LOG_PAGES (100) #define MHI_REGLEN 0x100 #define MHI_INIT 0 #define MHI_REINIT 1 enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR; enum mhi_msg_level mhi_ipc_msg_lvl = MHI_MSG_VERBOSE; Loading @@ -68,6 +70,8 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event, unsigned long data); static void mhi_ring_init_cb(void *user_data); static void mhi_update_state_info(uint32_t info); static int mhi_deinit(struct mhi_dev *mhi); static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify); void mhi_dev_read_from_host(struct mhi_dev *mhi, struct mhi_addr *transfer) { Loading Loading @@ -386,6 +390,9 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event, } mhi_update_state_info(MHI_STATE_CONNECTED); ep_pcie_mask_irq_event(mhi_ctx->phandle, EP_PCIE_INT_EVT_MHI_A7, true); break; case IPA_MHI_EVENT_DATA_AVAILABLE: rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP); Loading Loading @@ -1087,6 +1094,82 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) } } static int mhi_dev_abort(struct mhi_dev *mhi) { struct mhi_dev_channel *ch; struct mhi_dev_ring *ring; int ch_id = 0, rc = 0; /* Hard stop all the channels */ for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) { ring = &mhi->ring[ch_id + mhi->ch_ring_start]; if (ring->state == RING_STATE_UINT) continue; ch = &mhi->ch[ch_id]; mutex_lock(&ch->ch_lock); mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED; mutex_unlock(&ch->ch_lock); } /* Update ctrl node */ mhi_update_state_info(MHI_STATE_DISCONNECTED); flush_workqueue(mhi->ring_init_wq); flush_workqueue(mhi->pending_ring_wq); /* Initiate MHI IPA reset */ ipa_mhi_destroy(); /* Clean up initialized channels */ rc = mhi_deinit(mhi); if (rc) { pr_err("Error during mhi_deinit with %d\n", rc); return rc; } rc = mhi_dev_mmio_mask_chdb_interrupts(mhi_ctx); if (rc) { pr_err("Failed to enable channel db\n"); return rc; } rc = mhi_dev_mmio_disable_ctrl_interrupt(mhi_ctx); if (rc) { pr_err("Failed to enable control interrupt\n"); return rc; } rc = mhi_dev_mmio_disable_cmdb_interrupt(mhi_ctx); if (rc) { pr_err("Failed to enable command db\n"); return rc; } atomic_set(&mhi_ctx->re_init_done, 0); mhi_log(MHI_MSG_INFO, "Register a PCIe callback during re-init\n"); mhi_ctx->event_reg.events = EP_PCIE_EVENT_LINKUP; mhi_ctx->event_reg.user = mhi_ctx; mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK; mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up; mhi_ctx->event_reg.options = MHI_REINIT; rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg); if (rc) { pr_err("Failed to register for events from PCIe\n"); return rc; } /* Set RESET field to 0 */ mhi_dev_mmio_reset(mhi_ctx); return rc; } static void mhi_dev_scheduler(struct work_struct *work) { struct mhi_dev *mhi = container_of(work, Loading @@ -1096,6 +1179,7 @@ static void mhi_dev_scheduler(struct work_struct *work) struct mhi_dev_ring *ring; enum mhi_dev_state state; enum mhi_dev_event event = 0; bool mhi_reset = false; mutex_lock(&mhi_ctx->mhi_lock); /* Check for interrupts */ Loading @@ -1104,25 +1188,34 @@ static void mhi_dev_scheduler(struct work_struct *work) if (int_value & MHI_MMIO_CTRL_INT_STATUS_A7_MSK) { mhi_log(MHI_MSG_VERBOSE, "processing ctrl interrupt with %d\n", int_value); rc = mhi_dev_mmio_get_mhi_state(mhi, &state); rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); mutex_unlock(&mhi_ctx->mhi_lock); return; } if (mhi_reset) { mhi_log(MHI_MSG_VERBOSE, "processing mhi device reset\n"); rc = mhi_dev_abort(mhi); if (rc) pr_err("device reset failed:%d\n", rc); mutex_unlock(&mhi_ctx->mhi_lock); queue_work(mhi->ring_init_wq, &mhi->re_init); return; } rc = mhi_dev_get_event_notify(state, &event); if (rc) { pr_err("unsupported state :%d\n", state); mutex_unlock(&mhi_ctx->mhi_lock); return; goto fail; } rc = mhi_dev_notify_sm_event(event); if (rc) { pr_err("error sending SM event\n"); mutex_unlock(&mhi_ctx->mhi_lock); return; goto fail; } } Loading @@ -1137,6 +1230,7 @@ static void mhi_dev_scheduler(struct work_struct *work) /* get the specific channel interrupts */ mhi_dev_check_channel_interrupt(mhi); fail: mutex_unlock(&mhi_ctx->mhi_lock); if (mhi->config_iatu || mhi->mhi_int) Loading Loading @@ -1389,7 +1483,6 @@ int mhi_dev_suspend(struct mhi_dev *mhi) mhi_dev_write_to_host(mhi, &data_transfer); } mhi_update_state_info(MHI_STATE_DISCONNECTED); atomic_set(&mhi->mhi_dev_wake, 0); pm_relax(mhi->dev); Loading Loading @@ -1616,6 +1709,11 @@ int mhi_dev_read_channel(struct mhi_dev_client *handle_client, return -ENXIO; } if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) { pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info); return -ENODEV; } ch = handle_client->channel; ring = ch->ring; ch_id = ch->ch_id; Loading Loading @@ -1735,6 +1833,11 @@ int mhi_dev_write_channel(struct mhi_dev_client *handle_client, return -ENXIO; } if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) { pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info); return -ENODEV; } mutex_lock(&mhi_ctx->mhi_write_test); if (atomic_read(&mhi_ctx->is_suspended)) { Loading Loading @@ -1850,7 +1953,7 @@ static void mhi_dev_enable(struct work_struct *work) struct ep_pcie_msi_config msi_cfg; struct mhi_dev *mhi = container_of(work, struct mhi_dev, ring_init_cb_work); bool mhi_reset; enum mhi_dev_state state; uint32_t max_cnt = 0, bhi_intvec = 0; Loading Loading @@ -1898,7 +2001,7 @@ static void mhi_dev_enable(struct work_struct *work) } } rc = mhi_dev_mmio_get_mhi_state(mhi, &state); rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); return; Loading @@ -1907,7 +2010,7 @@ static void mhi_dev_enable(struct work_struct *work) while (state != MHI_DEV_M0_STATE && max_cnt < MHI_SUSPEND_TIMEOUT) { /* Wait for Host to set the M0 state */ msleep(MHI_SUSPEND_MIN); rc = mhi_dev_mmio_get_mhi_state(mhi, &state); rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); return; Loading Loading @@ -2096,6 +2199,39 @@ static int get_device_tree_data(struct platform_device *pdev) return 0; } static int mhi_deinit(struct mhi_dev *mhi) { int rc = 0, i = 0, ring_id = 0; struct mhi_dev_ring *ring; struct platform_device *pdev = mhi->pdev; ring_id = mhi->cfg.channels + mhi->cfg.event_rings + 1; for (i = 0; i < ring_id; i++) { ring = &mhi->ring[i]; if (ring->state == RING_STATE_UINT) continue; dma_free_coherent(mhi->dev, ring->ring_size * sizeof(union mhi_dev_ring_element_type), ring->ring_cache, ring->ring_cache_dma_handle); } for (i = 0; i < mhi->cfg.channels; i++) mutex_destroy(&mhi->ch[i].ch_lock); devm_kfree(&pdev->dev, mhi->mmio_backup); devm_kfree(&pdev->dev, mhi->ch); devm_kfree(&pdev->dev, mhi->ring); mhi_dev_sm_exit(mhi); mhi->mmio_initialized = false; return rc; } static int mhi_init(struct mhi_dev *mhi) { int rc = 0, i = 0; Loading Loading @@ -2129,15 +2265,101 @@ static int mhi_init(struct mhi_dev *mhi) if (!mhi->mmio_backup) return -ENOMEM; mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0); if (mhi_ipc_log == NULL) { dev_err(&pdev->dev, "Failed to create IPC logging context\n"); return 0; } static int mhi_dev_resume_mmio_mhi_reinit(struct mhi_dev *mhi_ctx) { int rc = 0; mutex_lock(&mhi_ctx->mhi_lock); if (atomic_read(&mhi_ctx->re_init_done)) { mhi_log(MHI_MSG_INFO, "Re_init done, return\n"); mutex_unlock(&mhi_ctx->mhi_lock); return 0; } rc = mhi_init(mhi_ctx); if (rc) { pr_err("Error initializing MHI MMIO with %d\n", rc); goto fail; } mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT | EP_PCIE_EVENT_PM_D3_COLD | EP_PCIE_EVENT_PM_D0 | EP_PCIE_EVENT_PM_RST_DEAST | EP_PCIE_EVENT_MHI_A7 | EP_PCIE_EVENT_LINKDOWN; mhi_ctx->event_reg.user = mhi_ctx; mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK; mhi_ctx->event_reg.callback = mhi_dev_sm_pcie_handler; rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg); if (rc) { pr_err("Failed to register for events from PCIe\n"); goto fail; } rc = ipa_register_ipa_ready_cb(mhi_ring_init_cb, mhi_ctx); if (rc < 0) { if (rc == -EEXIST) { mhi_ring_init_cb(mhi_ctx); } else { pr_err("Error calling IPA cb with %d\n", rc); goto fail; } } /* Invoke MHI SM when device is in RESET state */ rc = mhi_dev_sm_init(mhi_ctx); if (rc) { pr_err("%s: Error during SM init\n", __func__); goto fail; } /* set the env before setting the ready bit */ rc = mhi_dev_mmio_set_env(mhi_ctx, MHI_ENV_VALUE); if (rc) { pr_err("%s: env setting failed\n", __func__); goto fail; } /* All set, notify the host */ rc = mhi_dev_sm_set_ready(); if (rc) { pr_err("%s: unable to set ready bit\n", __func__); goto fail; } atomic_set(&mhi_ctx->is_suspended, 0); fail: atomic_set(&mhi_ctx->re_init_done, 1); mutex_unlock(&mhi_ctx->mhi_lock); return rc; } static void mhi_dev_reinit(struct work_struct *work) { struct mhi_dev *mhi_ctx = container_of(work, struct mhi_dev, re_init); enum ep_pcie_link_status link_state; int rc = 0; link_state = ep_pcie_get_linkstatus(mhi_ctx->phandle); if (link_state == EP_PCIE_LINK_ENABLED) { /* PCIe link is up with BME set */ rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx); if (rc) { pr_err("Failed to register for events from PCIe\n"); return; } } mhi_log(MHI_MSG_VERBOSE, "Wait for PCIe linkup\n"); } static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx) { struct platform_device *pdev; Loading @@ -2158,6 +2380,8 @@ static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx) INIT_WORK(&mhi_ctx->ring_init_cb_work, mhi_dev_enable); INIT_WORK(&mhi_ctx->re_init, mhi_dev_reinit); mhi_ctx->ring_init_wq = alloc_workqueue("mhi_ring_init_cb_wq", WQ_HIGHPRI, 0); if (!mhi_ctx->ring_init_wq) { Loading Loading @@ -2281,11 +2505,19 @@ void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify) return; } if (notify->options == MHI_INIT) { rc = mhi_dev_resume_mmio_mhi_init(mhi_ctx); if (rc) { pr_err("Error during MHI device initialization\n"); return; } } else if (notify->options == MHI_REINIT) { rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx); if (rc) { pr_err("Error during MHI device re-initialization\n"); return; } } } static int mhi_dev_probe(struct platform_device *pdev) Loading @@ -2298,6 +2530,12 @@ static int mhi_dev_probe(struct platform_device *pdev) pr_err("Error reading MHI Dev DT\n"); return rc; } mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0); if (mhi_ipc_log == NULL) { dev_err(&pdev->dev, "Failed to create IPC logging context\n"); } mhi_uci_init(); mhi_update_state_info(MHI_STATE_CONFIGURED); } Loading @@ -2316,6 +2554,7 @@ static int mhi_dev_probe(struct platform_device *pdev) mhi_ctx->event_reg.user = mhi_ctx; mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK; mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up; mhi_ctx->event_reg.options = MHI_INIT; rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg); Loading drivers/platform/msm/mhi_dev/mhi.h +5 −1 Original line number Diff line number Diff line Loading @@ -520,6 +520,7 @@ struct mhi_dev { u32 ipa_clnt_hndl[4]; struct workqueue_struct *ring_init_wq; struct work_struct ring_init_cb_work; struct work_struct re_init; /* EP PCIe registration */ struct ep_pcie_register_event event_reg; Loading @@ -529,6 +530,7 @@ struct mhi_dev { atomic_t write_active; atomic_t is_suspended; atomic_t mhi_dev_wake; atomic_t re_init_done; struct mutex mhi_write_test; u32 device_local_pa_base; u32 mhi_ep_msi_num; Loading Loading @@ -1050,8 +1052,10 @@ int mhi_dev_get_mhi_addr(struct mhi_dev *dev); * mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3. * @dev: MHI device structure. * @state: Pointer of type mhi_dev_state * @mhi_reset: MHI device reset from host. */ int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state); int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state, bool *mhi_reset); /** * mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event Loading drivers/platform/msm/mhi_dev/mhi_mmio.c +5 −1 Original line number Diff line number Diff line Loading @@ -258,7 +258,8 @@ int mhi_dev_mmio_disable_erdb_a7(struct mhi_dev *dev, uint32_t erdb_id) } EXPORT_SYMBOL(mhi_dev_mmio_disable_erdb_a7); int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state) int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state, bool *mhi_reset) { uint32_t reg_value = 0; int rc = 0; Loading @@ -277,6 +278,9 @@ int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state) if (rc) return rc; if (reg_value & MHICTRL_RESET_MASK) *mhi_reset = true; pr_debug("MHICTRL is 0x%x\n", reg_value); return 0; Loading drivers/platform/msm/mhi_dev/mhi_sm.c +21 −2 Original line number Diff line number Diff line Loading @@ -397,7 +397,8 @@ static bool mhi_sm_is_legal_pcie_event_on_state(enum mhi_dev_state curr_mstate, res = true; break; case EP_PCIE_EVENT_PM_D3_HOT: res = (curr_mstate == MHI_DEV_M3_STATE && res = ((curr_mstate == MHI_DEV_M3_STATE || curr_mstate == MHI_DEV_READY_STATE) && curr_dstate != MHI_SM_EP_PCIE_LINK_DISABLE); break; case EP_PCIE_EVENT_PM_D3_COLD: Loading Loading @@ -937,6 +938,24 @@ fail_init_wq: } EXPORT_SYMBOL(mhi_dev_sm_init); int mhi_dev_sm_exit(struct mhi_dev *mhi_dev) { MHI_SM_FUNC_ENTRY(); atomic_set(&mhi_sm_ctx->pending_device_events, 0); atomic_set(&mhi_sm_ctx->pending_pcie_events, 0); mhi_sm_debugfs_destroy(); flush_workqueue(mhi_sm_ctx->mhi_sm_wq); destroy_workqueue(mhi_sm_ctx->mhi_sm_wq); ipa_dma_destroy(); mutex_destroy(&mhi_sm_ctx->mhi_state_lock); devm_kfree(mhi_dev->dev, mhi_sm_ctx); mhi_sm_ctx = NULL; return 0; } EXPORT_SYMBOL(mhi_dev_sm_exit); /** * mhi_dev_sm_get_mhi_state() -Get current MHI state. * @state: return param Loading Loading @@ -983,7 +1002,7 @@ EXPORT_SYMBOL(mhi_dev_sm_get_mhi_state); */ int mhi_dev_sm_set_ready(void) { int res = -EAGAIN; int res = 0; int is_ready; enum mhi_dev_state state; Loading drivers/platform/msm/mhi_dev/mhi_sm.h +2 −1 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -41,6 +41,7 @@ enum mhi_dev_event { }; int mhi_dev_sm_init(struct mhi_dev *dev); int mhi_dev_sm_exit(struct mhi_dev *dev); int mhi_dev_sm_set_ready(void); int mhi_dev_notify_sm_event(enum mhi_dev_event event); int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state); Loading Loading
drivers/platform/msm/mhi_dev/mhi.c +259 −20 Original line number Diff line number Diff line Loading @@ -37,8 +37,8 @@ /* Wait time on the device for Host to set M0 state */ #define MHI_DEV_M0_MAX_CNT 30 /* Wait time before suspend/resume is complete */ #define MHI_SUSPEND_MIN 10000 #define MHI_SUSPEND_TIMEOUT 3000 #define MHI_SUSPEND_MIN 100 #define MHI_SUSPEND_TIMEOUT 600 #define MHI_MASK_CH_EV_LEN 32 #define MHI_RING_CMD_ID 0 #define MHI_RING_PRIMARY_EVT_ID 1 Loading @@ -58,6 +58,8 @@ #define MHI_IPC_LOG_PAGES (100) #define MHI_REGLEN 0x100 #define MHI_INIT 0 #define MHI_REINIT 1 enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR; enum mhi_msg_level mhi_ipc_msg_lvl = MHI_MSG_VERBOSE; Loading @@ -68,6 +70,8 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event, unsigned long data); static void mhi_ring_init_cb(void *user_data); static void mhi_update_state_info(uint32_t info); static int mhi_deinit(struct mhi_dev *mhi); static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify); void mhi_dev_read_from_host(struct mhi_dev *mhi, struct mhi_addr *transfer) { Loading Loading @@ -386,6 +390,9 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event, } mhi_update_state_info(MHI_STATE_CONNECTED); ep_pcie_mask_irq_event(mhi_ctx->phandle, EP_PCIE_INT_EVT_MHI_A7, true); break; case IPA_MHI_EVENT_DATA_AVAILABLE: rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP); Loading Loading @@ -1087,6 +1094,82 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) } } static int mhi_dev_abort(struct mhi_dev *mhi) { struct mhi_dev_channel *ch; struct mhi_dev_ring *ring; int ch_id = 0, rc = 0; /* Hard stop all the channels */ for (ch_id = 0; ch_id < mhi->cfg.channels; ch_id++) { ring = &mhi->ring[ch_id + mhi->ch_ring_start]; if (ring->state == RING_STATE_UINT) continue; ch = &mhi->ch[ch_id]; mutex_lock(&ch->ch_lock); mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED; mutex_unlock(&ch->ch_lock); } /* Update ctrl node */ mhi_update_state_info(MHI_STATE_DISCONNECTED); flush_workqueue(mhi->ring_init_wq); flush_workqueue(mhi->pending_ring_wq); /* Initiate MHI IPA reset */ ipa_mhi_destroy(); /* Clean up initialized channels */ rc = mhi_deinit(mhi); if (rc) { pr_err("Error during mhi_deinit with %d\n", rc); return rc; } rc = mhi_dev_mmio_mask_chdb_interrupts(mhi_ctx); if (rc) { pr_err("Failed to enable channel db\n"); return rc; } rc = mhi_dev_mmio_disable_ctrl_interrupt(mhi_ctx); if (rc) { pr_err("Failed to enable control interrupt\n"); return rc; } rc = mhi_dev_mmio_disable_cmdb_interrupt(mhi_ctx); if (rc) { pr_err("Failed to enable command db\n"); return rc; } atomic_set(&mhi_ctx->re_init_done, 0); mhi_log(MHI_MSG_INFO, "Register a PCIe callback during re-init\n"); mhi_ctx->event_reg.events = EP_PCIE_EVENT_LINKUP; mhi_ctx->event_reg.user = mhi_ctx; mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK; mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up; mhi_ctx->event_reg.options = MHI_REINIT; rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg); if (rc) { pr_err("Failed to register for events from PCIe\n"); return rc; } /* Set RESET field to 0 */ mhi_dev_mmio_reset(mhi_ctx); return rc; } static void mhi_dev_scheduler(struct work_struct *work) { struct mhi_dev *mhi = container_of(work, Loading @@ -1096,6 +1179,7 @@ static void mhi_dev_scheduler(struct work_struct *work) struct mhi_dev_ring *ring; enum mhi_dev_state state; enum mhi_dev_event event = 0; bool mhi_reset = false; mutex_lock(&mhi_ctx->mhi_lock); /* Check for interrupts */ Loading @@ -1104,25 +1188,34 @@ static void mhi_dev_scheduler(struct work_struct *work) if (int_value & MHI_MMIO_CTRL_INT_STATUS_A7_MSK) { mhi_log(MHI_MSG_VERBOSE, "processing ctrl interrupt with %d\n", int_value); rc = mhi_dev_mmio_get_mhi_state(mhi, &state); rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); mutex_unlock(&mhi_ctx->mhi_lock); return; } if (mhi_reset) { mhi_log(MHI_MSG_VERBOSE, "processing mhi device reset\n"); rc = mhi_dev_abort(mhi); if (rc) pr_err("device reset failed:%d\n", rc); mutex_unlock(&mhi_ctx->mhi_lock); queue_work(mhi->ring_init_wq, &mhi->re_init); return; } rc = mhi_dev_get_event_notify(state, &event); if (rc) { pr_err("unsupported state :%d\n", state); mutex_unlock(&mhi_ctx->mhi_lock); return; goto fail; } rc = mhi_dev_notify_sm_event(event); if (rc) { pr_err("error sending SM event\n"); mutex_unlock(&mhi_ctx->mhi_lock); return; goto fail; } } Loading @@ -1137,6 +1230,7 @@ static void mhi_dev_scheduler(struct work_struct *work) /* get the specific channel interrupts */ mhi_dev_check_channel_interrupt(mhi); fail: mutex_unlock(&mhi_ctx->mhi_lock); if (mhi->config_iatu || mhi->mhi_int) Loading Loading @@ -1389,7 +1483,6 @@ int mhi_dev_suspend(struct mhi_dev *mhi) mhi_dev_write_to_host(mhi, &data_transfer); } mhi_update_state_info(MHI_STATE_DISCONNECTED); atomic_set(&mhi->mhi_dev_wake, 0); pm_relax(mhi->dev); Loading Loading @@ -1616,6 +1709,11 @@ int mhi_dev_read_channel(struct mhi_dev_client *handle_client, return -ENXIO; } if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) { pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info); return -ENODEV; } ch = handle_client->channel; ring = ch->ring; ch_id = ch->ch_id; Loading Loading @@ -1735,6 +1833,11 @@ int mhi_dev_write_channel(struct mhi_dev_client *handle_client, return -ENXIO; } if (mhi_ctx->ctrl_info != MHI_STATE_CONNECTED) { pr_err("Channel not connected:%d\n", mhi_ctx->ctrl_info); return -ENODEV; } mutex_lock(&mhi_ctx->mhi_write_test); if (atomic_read(&mhi_ctx->is_suspended)) { Loading Loading @@ -1850,7 +1953,7 @@ static void mhi_dev_enable(struct work_struct *work) struct ep_pcie_msi_config msi_cfg; struct mhi_dev *mhi = container_of(work, struct mhi_dev, ring_init_cb_work); bool mhi_reset; enum mhi_dev_state state; uint32_t max_cnt = 0, bhi_intvec = 0; Loading Loading @@ -1898,7 +2001,7 @@ static void mhi_dev_enable(struct work_struct *work) } } rc = mhi_dev_mmio_get_mhi_state(mhi, &state); rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); return; Loading @@ -1907,7 +2010,7 @@ static void mhi_dev_enable(struct work_struct *work) while (state != MHI_DEV_M0_STATE && max_cnt < MHI_SUSPEND_TIMEOUT) { /* Wait for Host to set the M0 state */ msleep(MHI_SUSPEND_MIN); rc = mhi_dev_mmio_get_mhi_state(mhi, &state); rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); return; Loading Loading @@ -2096,6 +2199,39 @@ static int get_device_tree_data(struct platform_device *pdev) return 0; } static int mhi_deinit(struct mhi_dev *mhi) { int rc = 0, i = 0, ring_id = 0; struct mhi_dev_ring *ring; struct platform_device *pdev = mhi->pdev; ring_id = mhi->cfg.channels + mhi->cfg.event_rings + 1; for (i = 0; i < ring_id; i++) { ring = &mhi->ring[i]; if (ring->state == RING_STATE_UINT) continue; dma_free_coherent(mhi->dev, ring->ring_size * sizeof(union mhi_dev_ring_element_type), ring->ring_cache, ring->ring_cache_dma_handle); } for (i = 0; i < mhi->cfg.channels; i++) mutex_destroy(&mhi->ch[i].ch_lock); devm_kfree(&pdev->dev, mhi->mmio_backup); devm_kfree(&pdev->dev, mhi->ch); devm_kfree(&pdev->dev, mhi->ring); mhi_dev_sm_exit(mhi); mhi->mmio_initialized = false; return rc; } static int mhi_init(struct mhi_dev *mhi) { int rc = 0, i = 0; Loading Loading @@ -2129,15 +2265,101 @@ static int mhi_init(struct mhi_dev *mhi) if (!mhi->mmio_backup) return -ENOMEM; mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0); if (mhi_ipc_log == NULL) { dev_err(&pdev->dev, "Failed to create IPC logging context\n"); return 0; } static int mhi_dev_resume_mmio_mhi_reinit(struct mhi_dev *mhi_ctx) { int rc = 0; mutex_lock(&mhi_ctx->mhi_lock); if (atomic_read(&mhi_ctx->re_init_done)) { mhi_log(MHI_MSG_INFO, "Re_init done, return\n"); mutex_unlock(&mhi_ctx->mhi_lock); return 0; } rc = mhi_init(mhi_ctx); if (rc) { pr_err("Error initializing MHI MMIO with %d\n", rc); goto fail; } mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT | EP_PCIE_EVENT_PM_D3_COLD | EP_PCIE_EVENT_PM_D0 | EP_PCIE_EVENT_PM_RST_DEAST | EP_PCIE_EVENT_MHI_A7 | EP_PCIE_EVENT_LINKDOWN; mhi_ctx->event_reg.user = mhi_ctx; mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK; mhi_ctx->event_reg.callback = mhi_dev_sm_pcie_handler; rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg); if (rc) { pr_err("Failed to register for events from PCIe\n"); goto fail; } rc = ipa_register_ipa_ready_cb(mhi_ring_init_cb, mhi_ctx); if (rc < 0) { if (rc == -EEXIST) { mhi_ring_init_cb(mhi_ctx); } else { pr_err("Error calling IPA cb with %d\n", rc); goto fail; } } /* Invoke MHI SM when device is in RESET state */ rc = mhi_dev_sm_init(mhi_ctx); if (rc) { pr_err("%s: Error during SM init\n", __func__); goto fail; } /* set the env before setting the ready bit */ rc = mhi_dev_mmio_set_env(mhi_ctx, MHI_ENV_VALUE); if (rc) { pr_err("%s: env setting failed\n", __func__); goto fail; } /* All set, notify the host */ rc = mhi_dev_sm_set_ready(); if (rc) { pr_err("%s: unable to set ready bit\n", __func__); goto fail; } atomic_set(&mhi_ctx->is_suspended, 0); fail: atomic_set(&mhi_ctx->re_init_done, 1); mutex_unlock(&mhi_ctx->mhi_lock); return rc; } static void mhi_dev_reinit(struct work_struct *work) { struct mhi_dev *mhi_ctx = container_of(work, struct mhi_dev, re_init); enum ep_pcie_link_status link_state; int rc = 0; link_state = ep_pcie_get_linkstatus(mhi_ctx->phandle); if (link_state == EP_PCIE_LINK_ENABLED) { /* PCIe link is up with BME set */ rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx); if (rc) { pr_err("Failed to register for events from PCIe\n"); return; } } mhi_log(MHI_MSG_VERBOSE, "Wait for PCIe linkup\n"); } static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx) { struct platform_device *pdev; Loading @@ -2158,6 +2380,8 @@ static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx) INIT_WORK(&mhi_ctx->ring_init_cb_work, mhi_dev_enable); INIT_WORK(&mhi_ctx->re_init, mhi_dev_reinit); mhi_ctx->ring_init_wq = alloc_workqueue("mhi_ring_init_cb_wq", WQ_HIGHPRI, 0); if (!mhi_ctx->ring_init_wq) { Loading Loading @@ -2281,11 +2505,19 @@ void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify) return; } if (notify->options == MHI_INIT) { rc = mhi_dev_resume_mmio_mhi_init(mhi_ctx); if (rc) { pr_err("Error during MHI device initialization\n"); return; } } else if (notify->options == MHI_REINIT) { rc = mhi_dev_resume_mmio_mhi_reinit(mhi_ctx); if (rc) { pr_err("Error during MHI device re-initialization\n"); return; } } } static int mhi_dev_probe(struct platform_device *pdev) Loading @@ -2298,6 +2530,12 @@ static int mhi_dev_probe(struct platform_device *pdev) pr_err("Error reading MHI Dev DT\n"); return rc; } mhi_ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, "mhi", 0); if (mhi_ipc_log == NULL) { dev_err(&pdev->dev, "Failed to create IPC logging context\n"); } mhi_uci_init(); mhi_update_state_info(MHI_STATE_CONFIGURED); } Loading @@ -2316,6 +2554,7 @@ static int mhi_dev_probe(struct platform_device *pdev) mhi_ctx->event_reg.user = mhi_ctx; mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK; mhi_ctx->event_reg.callback = mhi_dev_resume_init_with_link_up; mhi_ctx->event_reg.options = MHI_INIT; rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg); Loading
drivers/platform/msm/mhi_dev/mhi.h +5 −1 Original line number Diff line number Diff line Loading @@ -520,6 +520,7 @@ struct mhi_dev { u32 ipa_clnt_hndl[4]; struct workqueue_struct *ring_init_wq; struct work_struct ring_init_cb_work; struct work_struct re_init; /* EP PCIe registration */ struct ep_pcie_register_event event_reg; Loading @@ -529,6 +530,7 @@ struct mhi_dev { atomic_t write_active; atomic_t is_suspended; atomic_t mhi_dev_wake; atomic_t re_init_done; struct mutex mhi_write_test; u32 device_local_pa_base; u32 mhi_ep_msi_num; Loading Loading @@ -1050,8 +1052,10 @@ int mhi_dev_get_mhi_addr(struct mhi_dev *dev); * mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3. * @dev: MHI device structure. * @state: Pointer of type mhi_dev_state * @mhi_reset: MHI device reset from host. */ int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state); int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state, bool *mhi_reset); /** * mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event Loading
drivers/platform/msm/mhi_dev/mhi_mmio.c +5 −1 Original line number Diff line number Diff line Loading @@ -258,7 +258,8 @@ int mhi_dev_mmio_disable_erdb_a7(struct mhi_dev *dev, uint32_t erdb_id) } EXPORT_SYMBOL(mhi_dev_mmio_disable_erdb_a7); int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state) int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state, bool *mhi_reset) { uint32_t reg_value = 0; int rc = 0; Loading @@ -277,6 +278,9 @@ int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state) if (rc) return rc; if (reg_value & MHICTRL_RESET_MASK) *mhi_reset = true; pr_debug("MHICTRL is 0x%x\n", reg_value); return 0; Loading
drivers/platform/msm/mhi_dev/mhi_sm.c +21 −2 Original line number Diff line number Diff line Loading @@ -397,7 +397,8 @@ static bool mhi_sm_is_legal_pcie_event_on_state(enum mhi_dev_state curr_mstate, res = true; break; case EP_PCIE_EVENT_PM_D3_HOT: res = (curr_mstate == MHI_DEV_M3_STATE && res = ((curr_mstate == MHI_DEV_M3_STATE || curr_mstate == MHI_DEV_READY_STATE) && curr_dstate != MHI_SM_EP_PCIE_LINK_DISABLE); break; case EP_PCIE_EVENT_PM_D3_COLD: Loading Loading @@ -937,6 +938,24 @@ fail_init_wq: } EXPORT_SYMBOL(mhi_dev_sm_init); int mhi_dev_sm_exit(struct mhi_dev *mhi_dev) { MHI_SM_FUNC_ENTRY(); atomic_set(&mhi_sm_ctx->pending_device_events, 0); atomic_set(&mhi_sm_ctx->pending_pcie_events, 0); mhi_sm_debugfs_destroy(); flush_workqueue(mhi_sm_ctx->mhi_sm_wq); destroy_workqueue(mhi_sm_ctx->mhi_sm_wq); ipa_dma_destroy(); mutex_destroy(&mhi_sm_ctx->mhi_state_lock); devm_kfree(mhi_dev->dev, mhi_sm_ctx); mhi_sm_ctx = NULL; return 0; } EXPORT_SYMBOL(mhi_dev_sm_exit); /** * mhi_dev_sm_get_mhi_state() -Get current MHI state. * @state: return param Loading Loading @@ -983,7 +1002,7 @@ EXPORT_SYMBOL(mhi_dev_sm_get_mhi_state); */ int mhi_dev_sm_set_ready(void) { int res = -EAGAIN; int res = 0; int is_ready; enum mhi_dev_state state; Loading
drivers/platform/msm/mhi_dev/mhi_sm.h +2 −1 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -41,6 +41,7 @@ enum mhi_dev_event { }; int mhi_dev_sm_init(struct mhi_dev *dev); int mhi_dev_sm_exit(struct mhi_dev *dev); int mhi_dev_sm_set_ready(void); int mhi_dev_notify_sm_event(enum mhi_dev_event event); int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state); Loading