From cf2a299dea373ee5dfea43c3e2e7524f5106ed86 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 2 Jan 2020 19:05:07 -0800 Subject: [PATCH 1/2] mhi: cntrl: qcom: disable boot logger after forced suspend Prioritize handling of forced suspend/resume cycle at mission mode entry and disable boot logger channel after the cycle has completed to avoid race conditions. Change-Id: Iddc3d560fa687399434cc8ad51c08509ddfadf70 Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/controllers/mhi_arch_qcom.c | 23 +++++++++++++-------- drivers/bus/mhi/controllers/mhi_qcom.c | 3 ++- drivers/bus/mhi/controllers/mhi_qcom.h | 7 ++++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c index beffe745cdf1..56ced4080807 100644 --- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c @@ -1,5 +1,5 @@ // 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 #include @@ -310,7 +310,6 @@ static void mhi_boot_monitor(void *data, async_cookie_t cookie) struct mhi_controller *mhi_cntrl = data; struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); struct arch_info *arch_info = mhi_dev->arch_info; - struct mhi_device *boot_dev; /* 15 sec timeout for booting device */ const u32 timeout = msecs_to_jiffies(15000); @@ -323,15 +322,10 @@ static void mhi_boot_monitor(void *data, async_cookie_t cookie) ipc_log_string(arch_info->boot_ipc_log, HLOG "Device current ee = %s\n", 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_unprepare_from_transfer(boot_dev); - + /* if we successfully booted to amss, enable runtime pm */ + if (mhi_cntrl->ee == MHI_EE_AMSS) if (!mhi_dev->drv_supported || arch_info->drv_connected) pm_runtime_allow(&mhi_dev->pci_dev->dev); - } } int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) @@ -346,6 +340,17 @@ int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) return 0; } +void mhi_arch_mission_mode_enter(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 mhi_device *boot_dev = arch_info->boot_dev; + + /* disable boot logger channel */ + if (boot_dev) + mhi_unprepare_from_transfer(boot_dev); +} + static int mhi_arch_pcie_scale_bw(struct mhi_controller *mhi_cntrl, struct pci_dev *pci_dev, struct mhi_link_info *link_info) diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 86a2f992ed6a..8ae09fcb4012 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -1,5 +1,5 @@ // 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 #include @@ -636,6 +636,7 @@ static void mhi_status_cb(struct mhi_controller *mhi_cntrl, if (!ret) mhi_runtime_resume(dev); pm_runtime_put(dev); + mhi_arch_mission_mode_enter(mhi_cntrl); break; default: MHI_ERR("Unhandled cb:0x%x\n", reason); diff --git a/drivers/bus/mhi/controllers/mhi_qcom.h b/drivers/bus/mhi/controllers/mhi_qcom.h index 36048633602e..da03dc12a6a2 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.h +++ b/drivers/bus/mhi/controllers/mhi_qcom.h @@ -1,5 +1,5 @@ /* 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_QCOM_ #define _MHI_QCOM_ @@ -68,6 +68,7 @@ int mhi_pci_probe(struct pci_dev *pci_dev, #ifdef CONFIG_ARCH_QCOM +void mhi_arch_mission_mode_enter(struct mhi_controller *mhi_cntrl); int mhi_arch_power_up(struct mhi_controller *mhi_cntrl); int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl); void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl); @@ -100,6 +101,10 @@ static inline int mhi_arch_power_up(struct mhi_controller *mhi_cntrl) return 0; } +static inline void mhi_arch_mission_mode_enter(struct mhi_controller *mhi_cntrl) +{ +} + #endif #endif /* _MHI_QCOM_ */ From d0a4940862ff9cbd5b50aa8eec24e7170f0b7df7 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 19 Dec 2019 18:01:57 -0800 Subject: [PATCH 2/2] mhi: core: fix fast forward recycling of event rings Some low priority event rings operate on a fast forwarding mechanism where only the latest event is processed and the rest are skipped. The recycle API only handles updating the context write pointer in sequence which causes an out of bounds doorbell issued to the device due to mismatched values. Add another API to support handling updates for context write pointer separately with the fast forwarding use case. Change-Id: If628b49e063d14920fe734ebd113c9c4c733204b Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_main.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 0cd40bf99786..47e26304ee16 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -292,6 +292,29 @@ static void mhi_recycle_ev_ring_element(struct mhi_controller *mhi_cntrl, smp_wmb(); } +static void mhi_recycle_fwd_ev_ring_element(struct mhi_controller *mhi_cntrl, + struct mhi_ring *ring) +{ + dma_addr_t ctxt_wp; + + /* update the WP */ + ring->wp += ring->el_size; + if (ring->wp >= (ring->base + ring->len)) + ring->wp = ring->base; + + /* update the context WP based on the RP to support fast forwarding */ + ctxt_wp = ring->iommu_base + (ring->wp - ring->base); + *ring->ctxt_wp = ctxt_wp; + + /* update the RP */ + ring->rp += ring->el_size; + if (ring->rp >= (ring->base + ring->len)) + ring->rp = ring->base; + + /* visible to other cores */ + smp_wmb(); +} + static bool mhi_is_ring_full(struct mhi_controller *mhi_cntrl, struct mhi_ring *ring) { @@ -1451,7 +1474,7 @@ int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl, 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_ev_ring_element(mhi_cntrl, ev_ring); + mhi_recycle_fwd_ev_ring_element(mhi_cntrl, ev_ring); read_lock_bh(&mhi_cntrl->pm_lock); if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))