From 9bc84cff6e433d76e762deb52c01db379aff0152 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Wed, 22 Sep 2021 23:23:59 +0530 Subject: [PATCH] msm: ep_pcie: Send pme from panic/reboot handler while in D3hot Send pme from panic/reboot handler if the device is in D3hot to bring device state back to D0. This helps PBL to take retrain the link gracefully as PBL didn't have ability to bring the device our of D3hot state. Also send MHI to syserr, so that MHI host wont timeout on M0ack. Change-Id: I3de45cab30caa332bd00abe8b1ed1487d7889d5f Signed-off-by: Veerabhadrarao Badiganti --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 1 + drivers/platform/msm/ep_pcie/ep_pcie_core.c | 64 +++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 2090aa21755f..9e740d21f82f 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -359,6 +359,7 @@ struct ep_pcie_dev_t { bool m2_autonomous; bool mhi_soc_reset_en; bool aoss_rst_clear; + bool avoid_reboot_in_d3hot; u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 13f49bc235d1..94149541e3f5 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -3190,6 +3193,49 @@ int ep_pcie_core_config_db_routing(struct ep_pcie_db_config chdb_cfg, return 0; } +static int ep_pcie_core_panic_reboot_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + struct ep_pcie_dev_t *dev = &ep_pcie_dev; + u32 mhi_syserr = BIT(2)|(0xff << 8); + unsigned long irqsave_flags; + + if (!ep_pcie_dev.avoid_reboot_in_d3hot) + goto out; + + /* If the device is in D3hot state, bring it to D0 */ + spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + if (dev->l23_ready && atomic_read(&dev->perst_deast)) { + + EP_PCIE_INFO(dev, + "PCIe V%d got %s notification while in D3hot\n", + dev->rev, reason ? "reboot":"panic/die"); + + /* Set MHI to SYSERR state */ + if (dev->config_mmio_init) + ep_pcie_write_reg(dev->mmio, PCIE20_MHISTATUS, + mhi_syserr); + /* Bring device out of D3hot */ + ep_pcie_core_issue_inband_pme(); + } + spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); + +out: + return NOTIFY_DONE; +} + +static struct notifier_block ep_pcie_core_reboot_notifier = { + .notifier_call = ep_pcie_core_panic_reboot_callback, +}; + +static struct notifier_block ep_pcie_core_die_notifier = { + .notifier_call = ep_pcie_core_panic_reboot_callback, +}; + +static struct notifier_block ep_pcie_core_panic_notifier = { + .notifier_call = ep_pcie_core_panic_reboot_callback, +}; + struct ep_pcie_hw hw_drv = { .register_event = ep_pcie_core_register_event, .deregister_event = ep_pcie_core_deregister_event, @@ -3361,6 +3407,13 @@ static int ep_pcie_probe(struct platform_device *pdev) "PCIe V%d: MHI M2 autonomous is %s enabled\n", ep_pcie_dev.rev, ep_pcie_dev.m2_autonomous ? "" : "not"); + ep_pcie_dev.avoid_reboot_in_d3hot = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,avoid-reboot-in-d3hot"); + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: PME during reboot/panic (in D3hot) is %s needed\n", + ep_pcie_dev.rev, ep_pcie_dev.avoid_reboot_in_d3hot ? "" : "not"); + ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,mhi-soc-reset-offset", &ep_pcie_dev.mhi_soc_reset_offset); @@ -3453,6 +3506,12 @@ static int ep_pcie_probe(struct platform_device *pdev) if (ret && !ep_pcie_debug_keep_resource) goto irq_deinit; + register_reboot_notifier(&ep_pcie_core_reboot_notifier); + /* Handler for wilful crash like BUG_ON */ + register_die_notifier(&ep_pcie_core_die_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &ep_pcie_core_panic_notifier); + qcom_edma_init(&pdev->dev); if (!ep_pcie_dev.perst_enum) @@ -3476,6 +3535,11 @@ static int __exit ep_pcie_remove(struct platform_device *pdev) { pr_debug("%s\n", __func__); + unregister_reboot_notifier(&ep_pcie_core_reboot_notifier); + unregister_die_notifier(&ep_pcie_core_die_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &ep_pcie_core_panic_notifier); + ep_pcie_irq_deinit(&ep_pcie_dev); ep_pcie_vreg_deinit(&ep_pcie_dev); ep_pcie_pipe_clk_deinit(&ep_pcie_dev);