From 0c4ad0f29e795d4dfccaa3b22d64f7c1d18fba4c Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Tue, 8 Dec 2020 23:53:25 +0530 Subject: [PATCH] msm: pcie : Notify client driver on reading FF's Disable access to PCIE config space registers and notify client driver to recover link on reading PCIE endpoint config registers as FF's. Change-Id: Iea6b25036bc6d967d6598d08348bb41fc18ef304 Signed-off-by: Vivek Pernamitta --- drivers/pci/controller/pci-msm.c | 41 ++++++++++++++++++++++++++++++-- include/linux/msm_pcie.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 6141ab607025..29744c7b377a 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -762,6 +762,8 @@ struct msm_pcie_dev_t { struct pinctrl_state *pins_default; struct pinctrl_state *pins_sleep; struct msm_pcie_device_info pcidev_table[MAX_DEVICE_NUM]; + bool config_recovery; + struct work_struct link_recover_wq; struct msm_pcie_drv_info *drv_info; @@ -2946,14 +2948,22 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, if (dev->shadow_en) { if (rd_val == PCIE_LINK_DOWN && - (readl_relaxed(config_base) == PCIE_LINK_DOWN)) + (readl_relaxed(config_base) == PCIE_LINK_DOWN)) { PCIE_ERR(dev, "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", rc_idx, bus->number, devfn, where, size); - else + if (dev->config_recovery) { + PCIE_ERR(dev, + "RC%d link recovery schedule\n", + rc_idx); + dev->cfg_access = false; + schedule_work(&dev->link_recover_wq); + } + } else { msm_pcie_save_shadow(dev, word_offset, wr_val, bdf, rc); + } } PCIE_DBG3(dev, @@ -4859,6 +4869,16 @@ static void handle_wake_func(struct work_struct *work) mutex_unlock(&dev->recovery_lock); } +static void handle_link_recover(struct work_struct *work) +{ + struct msm_pcie_dev_t *dev = container_of(work, struct msm_pcie_dev_t, + link_recover_wq); + + PCIE_DBG(dev, "PCIe: link recover start for RC%d\n", dev->rc_idx); + + msm_pcie_notify_client(dev, MSM_PCIE_EVENT_LINK_RECOVER); +} + static irqreturn_t handle_aer_irq(int irq, void *data) { struct msm_pcie_dev_t *dev = data; @@ -6000,6 +6020,14 @@ static int msm_pcie_probe(struct platform_device *pdev) msm_pcie_gpio_deinit(pcie_dev); goto decrease_rc_num; } + pcie_dev->config_recovery = of_property_read_bool(of_node, + "qcom,config-recovery"); + if (pcie_dev->config_recovery) { + PCIE_DUMP(pcie_dev, + "PCIe RC%d config space recovery enabled\n", + pcie_dev->rc_idx); + INIT_WORK(&pcie_dev->link_recover_wq, handle_link_recover); + } drv_supported = of_property_read_bool(of_node, "qcom,drv-supported"); if (drv_supported) { @@ -6755,6 +6783,15 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, pcie_dev->suspending = true; spin_unlock_irqrestore(&pcie_dev->irq_lock, irqsave_flags); + if (pcie_dev->config_recovery) { + if (work_pending(&pcie_dev->link_recover_wq)) { + PCIE_DBG(pcie_dev, + "RC%d: cancel link_recover_wq at pm suspend\n", + pcie_dev->rc_idx); + cancel_work_sync(&pcie_dev->link_recover_wq); + } + } + if (!pcie_dev->power_on) { PCIE_DBG(pcie_dev, "PCIe: power of RC%d has been turned off.\n", diff --git a/include/linux/msm_pcie.h b/include/linux/msm_pcie.h index 3a5fa760ee45..070bf38f2b52 100644 --- a/include/linux/msm_pcie.h +++ b/include/linux/msm_pcie.h @@ -32,6 +32,7 @@ enum msm_pcie_event { MSM_PCIE_EVENT_L1SS_TIMEOUT = BIT(3), MSM_PCIE_EVENT_DRV_CONNECT = BIT(4), MSM_PCIE_EVENT_DRV_DISCONNECT = BIT(5), + MSM_PCIE_EVENT_LINK_RECOVER = BIT(6), }; enum msm_pcie_trigger {