From 3e5d5f6b7701b8b3b352b8454977fc29a899fee1 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 12 Jun 2020 12:30:15 -0700 Subject: [PATCH 1/2] pci: controller: msm: Poll for L0s state when disallowing L1 If L0s link state is enabled, API to disallow L1 also needs to poll for L0s while checking for L0. It is possible that link goes to L0s from L0 by the time LTSSM state is checked again. Change-Id: Ib614860dad8c92a55f993cdb1c38bf8ebfca17a2 Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index bd3c94137c33..ce3edb01f0c3 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -2274,6 +2274,19 @@ static int msm_pcie_is_link_up(struct msm_pcie_dev_t *dev) PCIE20_CAP_LINKCTRLSTATUS) & BIT(29); } +static bool msm_pcie_check_ltssm_state(struct msm_pcie_dev_t *dev, u32 state) +{ + u32 ltssm; + + ltssm = readl_relaxed(dev->parf + PCIE20_PARF_LTSSM) & + MSM_PCIE_LTSSM_MASK; + + if (ltssm == state) + return true; + + return false; +} + /** * msm_pcie_iatu_config - configure outbound address translation region * @dev: root commpex @@ -5768,9 +5781,9 @@ int msm_pcie_prevent_l1(struct pci_dev *pci_dev) PCI_EXP_LNKCTL_ASPM_L1, 0); msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(5)); - /* confirm link is in L0 */ - while (((readl_relaxed(pcie_dev->parf + PCIE20_PARF_LTSSM) & - MSM_PCIE_LTSSM_MASK)) != MSM_PCIE_LTSSM_L0) { + /* confirm link is in L0/L0s */ + while (!msm_pcie_check_ltssm_state(pcie_dev, MSM_PCIE_LTSSM_L0) && + !msm_pcie_check_ltssm_state(pcie_dev, MSM_PCIE_LTSSM_L0S)) { if (unlikely(cnt++ >= cnt_max)) { PCIE_ERR(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: failed to transition to L0\n", From 743aaee1de7ea8dbc06be0c4d56d5b9e8378f138 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 12 Jun 2020 15:11:07 -0700 Subject: [PATCH 2/2] pci: controller: msm: Prevent L0s before switching Gen speed Link needs to be in L0 before Gen switching is performed. Programming target link speed to HW does not take effect in L0s. After disabling L0s perform a EP config read if the link is in L0s in order to bring the link to L0 for Gen speed switch. Change-Id: Iabe790b90b1da0421c2d59a7f2e053e5e8fe77c9 Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index ce3edb01f0c3..41c7d3dd8c64 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -5811,6 +5811,24 @@ err: } EXPORT_SYMBOL(msm_pcie_prevent_l1); +static int msm_pcie_read_devid_all(struct pci_dev *pdev, void *dev) +{ + u16 device_id; + + pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); + + return 0; +} + +static void msm_pcie_poll_for_l0_from_l0s(struct msm_pcie_dev_t *dev) +{ + if (!dev->l0s_supported) + return; + + while (!msm_pcie_check_ltssm_state(dev, MSM_PCIE_LTSSM_L0)) + pci_walk_bus(dev->dev->bus, msm_pcie_read_devid_all, dev); +} + int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, u16 target_link_width) { @@ -5884,6 +5902,11 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, if (ret) return ret; + msm_pcie_config_l0s_disable_all(pcie_dev, root_pci_dev->bus); + + /* in case link is already in L0s bring link back to L0 */ + msm_pcie_poll_for_l0_from_l0s(pcie_dev); + if (target_link_speed > current_link_speed) msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed); @@ -5908,6 +5931,7 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, PCIE_DBG(pcie_dev, "PCIe: RC%d: successfully switched link bandwidth\n", pcie_dev->rc_idx); out: + msm_pcie_config_l0s_enable_all(pcie_dev); msm_pcie_allow_l1(root_pci_dev); return ret;