From 32de0804b1379d126033893ef70955fbbb77eb91 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Tue, 12 Mar 2024 20:27:22 -0700 Subject: [PATCH] msm: ep_pcie: Disable hot reset and ignore linkdown Intel host tends to retrain the link if device doesn't send PM_Enter_L23 in time, leading to linkdown and hot reset in device side. The hot reset here even results to PERST# timeout and device crash to PBL, which is not expected. Since we are in the entry of shutdown the link when linkdown happen, it makes sense to ignore the linkdown. To avoid device crash because of PERST# timeout, disable hot reset in pm_turnoff irq and reenable it when we do linktrain again. Change-Id: I87961faaae2a14c9a5e7d24543b416914076dd2e Signed-off-by: Qiang Yu Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 2 + drivers/platform/msm/ep_pcie/ep_pcie_core.c | 51 ++++++++++++++++++++- include/linux/msm_ep_pcie.h | 1 + 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 34b7a56b2217..5e3d8a02279b 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.*/ +/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.*/ #ifndef __EP_PCIE_COM_H #define __EP_PCIE_COM_H @@ -429,6 +430,7 @@ struct ep_pcie_dev_t { struct clk *pipe_clk_mux; struct clk *pipe_clk_ext_src; struct clk *ref_clk_src; + u32 tcsr_hot_reset_en_offset; }; extern struct ep_pcie_dev_t ep_pcie_dev; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index d0b8e3f386a3..591f7cb47d38 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.*/ +/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.*/ /* * MSM PCIe endpoint core driver. @@ -37,6 +38,7 @@ #define PCIE_MHI_STATUS(n) ((n) + 0x148) #define TCSR_PERST_SEPARATION_ENABLE 0x270 #define TCSR_PCIE_RST_SEPARATION 0x3F8 +#define TCSR_HOT_RESET_EN 0x3e8 #define PCIE_ISSUE_WAKE 1 #define PCIE_MHI_FWD_STATUS_MIN 5000 #define PCIE_MHI_FWD_STATUS_MAX 5100 @@ -1815,6 +1817,13 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) */ writel_relaxed(0, dev->tcsr_perst_en + TCSR_PERST_SEPARATION_ENABLE); + + /* + * Re-enable hot reset before link up since we disable it + * in pm_turnoff irq. + */ + ep_pcie_write_reg_field(dev->tcsr_perst_en, + ep_pcie_dev.tcsr_hot_reset_en_offset, BIT(0), BIT(0)); } /* check link status during initial bootup */ @@ -2280,6 +2289,10 @@ static irqreturn_t ep_pcie_handle_linkdown_irq(int irq, void *data) EP_PCIE_DBG(dev, "PCIe V%d:Linkdown IRQ happened when the link is suspending\n", dev->rev); + } else if (dev->link_status == EP_PCIE_LINK_IN_L23READY) { + EP_PCIE_DBG(dev, + "PCIe V%d:Linkdown IRQ happened when link goes to l23ready\n", + dev->rev); } else { dev->link_status = EP_PCIE_LINK_DISABLED; EP_PCIE_ERR(dev, "PCIe V%d:PCIe link is down for %ld times\n", @@ -2320,13 +2333,29 @@ static irqreturn_t ep_pcie_handle_pm_turnoff_irq(int irq, void *data) spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + if (!dev->tcsr_not_supported) + /* + * Some hosts will try to recovery link if it doesn't receive PM_L23_Enter + * within 10ms after sending PME turn off, in which case if Hot reset is + * enabled, PERST# timeout circuit will start to work. If it measures that + * the link doesn't enter L0 within a predetermined time, device will crash + * with PERST_TIMEOUT_RESET_STATUS set to 1. + * + * Note that PERST# timeout circuit monitors the Detect to L0 transition and + * it gets activated in two scenario: + * 1) When PERST# gets de-asserted and perst-separation is enabled. + * 2) When hot-reset is enabled and link training is initiated. + */ + ep_pcie_write_reg_field(dev->tcsr_perst_en, + ep_pcie_dev.tcsr_hot_reset_en_offset, BIT(0), 0); + dev->pm_to_counter++; EP_PCIE_DBG2(dev, "PCIe V%d: No. %ld PM_TURNOFF is received\n", dev->rev, dev->pm_to_counter); EP_PCIE_DBG2(dev, "PCIe V%d: Put the link into L23\n", dev->rev); ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(2)); - + dev->link_status = EP_PCIE_LINK_IN_L23READY; spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); return IRQ_HANDLED; @@ -2943,6 +2972,11 @@ enum ep_pcie_link_status ep_pcie_core_get_linkstatus(void) return EP_PCIE_LINK_DISABLED; } + if (dev->link_status == EP_PCIE_LINK_IN_L23READY) { + EP_PCIE_DBG(dev, "PCIe V%d: PCIe endpoint has sent PM_ENTER_L23\n", dev->rev); + return EP_PCIE_LINK_IN_L23READY; + } + bme = readl_relaxed(dev->dm_core + PCIE20_COMMAND_STATUS) & BIT(2); if (bme) { @@ -3499,6 +3533,21 @@ static int ep_pcie_probe(struct platform_device *pdev) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: tcsr pcie perst is %s supported\n", ep_pcie_dev.rev, ep_pcie_dev.tcsr_not_supported ? "not" : ""); + if (!ep_pcie_dev.tcsr_not_supported) { + + ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,tcsr-hot-reset-en-offset", + &ep_pcie_dev.tcsr_hot_reset_en_offset); + if (ret) { + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: TCSR Hot Reset Enable Offset is not supplied from DT", + ep_pcie_dev.rev); + ep_pcie_dev.tcsr_hot_reset_en_offset = TCSR_HOT_RESET_EN; + } + + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: TCSR Hot Reset Enable Offset: 0x%x\n", + ep_pcie_dev.rev, ep_pcie_dev.tcsr_hot_reset_en_offset); + } ep_pcie_dev.aoss_rst_clear = of_property_read_bool ((&pdev->dev)->of_node, diff --git a/include/linux/msm_ep_pcie.h b/include/linux/msm_ep_pcie.h index d98ed7b13984..82da45762bfc 100644 --- a/include/linux/msm_ep_pcie.h +++ b/include/linux/msm_ep_pcie.h @@ -20,6 +20,7 @@ enum ep_pcie_link_status { EP_PCIE_LINK_DISABLED, EP_PCIE_LINK_UP, EP_PCIE_LINK_ENABLED, + EP_PCIE_LINK_IN_L23READY, }; enum ep_pcie_event {