Loading drivers/pci/controller/pci-msm.c +103 −20 Original line number Diff line number Diff line Loading @@ -725,6 +725,8 @@ struct msm_pcie_dev_t { struct mutex recovery_lock; spinlock_t wakeup_lock; spinlock_t irq_lock; struct mutex aspm_lock; int prevent_l1; ulong linkdown_counter; ulong link_turned_on_counter; ulong link_turned_off_counter; Loading Loading @@ -1392,6 +1394,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->wake_counter); PCIE_DBG_FS(dev, "link_check_max_count: %u\n", dev->link_check_max_count); PCIE_DBG_FS(dev, "prevent_l1: %d\n", dev->prevent_l1); PCIE_DBG_FS(dev, "target_link_speed: 0x%x\n", dev->target_link_speed); PCIE_DBG_FS(dev, "link_turned_on_counter: %lu\n", Loading Loading @@ -6051,20 +6055,6 @@ static int msm_pcie_link_retrain(struct msm_pcie_dev_t *pcie_dev, u32 cnt_max = 1000; /* 100ms timeout */ u32 link_status_lbms_mask = PCI_EXP_LNKSTA_LBMS << PCI_EXP_LNKCTL; cnt = 0; /* confirm link is in L0 */ while (((readl_relaxed(pcie_dev->parf + PCIE20_PARF_LTSSM) & MSM_PCIE_LTSSM_MASK)) != MSM_PCIE_LTSSM_L0) { if (unlikely(cnt++ >= cnt_max)) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to transition to L0\n", pcie_dev->rc_idx); return -EIO; } usleep_range(100, 105); } /* link retrain */ msm_pcie_config_clear_set_dword(pci_dev, pci_dev->pcie_cap + PCI_EXP_LNKCTL, Loading Loading @@ -6113,6 +6103,99 @@ static int msm_pcie_set_link_width(struct msm_pcie_dev_t *pcie_dev, return 0; } void msm_pcie_allow_l1(struct pci_dev *pci_dev) { struct pci_dev *root_pci_dev; struct msm_pcie_dev_t *pcie_dev; root_pci_dev = pci_find_pcie_root_port(pci_dev); if (!root_pci_dev) return; pcie_dev = PCIE_BUS_PRIV_DATA(root_pci_dev->bus); mutex_lock(&pcie_dev->aspm_lock); if (unlikely(--pcie_dev->prevent_l1 < 0)) PCIE_ERR(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: unbalanced prevent_l1: %d < 0\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), pcie_dev->prevent_l1); if (pcie_dev->prevent_l1) { mutex_unlock(&pcie_dev->aspm_lock); return; } msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0); /* enable L1 */ msm_pcie_write_mask(pcie_dev->dm_core + (root_pci_dev->pcie_cap + PCI_EXP_LNKCTL), 0, PCI_EXP_LNKCTL_ASPM_L1); PCIE_DBG2(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: exit\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); mutex_unlock(&pcie_dev->aspm_lock); } EXPORT_SYMBOL(msm_pcie_allow_l1); int msm_pcie_prevent_l1(struct pci_dev *pci_dev) { struct pci_dev *root_pci_dev; struct msm_pcie_dev_t *pcie_dev; u32 cnt = 0; u32 cnt_max = 1000; /* 100ms timeout */ int ret = 0; root_pci_dev = pci_find_pcie_root_port(pci_dev); if (!root_pci_dev) return -ENODEV; pcie_dev = PCIE_BUS_PRIV_DATA(root_pci_dev->bus); /* disable L1 */ mutex_lock(&pcie_dev->aspm_lock); if (pcie_dev->prevent_l1++) { mutex_unlock(&pcie_dev->aspm_lock); return 0; } msm_pcie_write_mask(pcie_dev->dm_core + (root_pci_dev->pcie_cap + PCI_EXP_LNKCTL), 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) { if (unlikely(cnt++ >= cnt_max)) { PCIE_ERR(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: failed to transition to L0\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); ret = -EIO; goto err; } usleep_range(100, 105); } PCIE_DBG2(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: exit\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); mutex_unlock(&pcie_dev->aspm_lock); return 0; err: mutex_unlock(&pcie_dev->aspm_lock); msm_pcie_allow_l1(pci_dev); return ret; } EXPORT_SYMBOL(msm_pcie_prevent_l1); int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, u16 target_link_width) { Loading Loading @@ -6162,9 +6245,10 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, PCI_EXP_LNKSTA_CLS, target_link_speed); /* disable link L1. Need to be in L0 for gen switch */ msm_pcie_config_l1(pcie_dev, root_pci_dev, false); msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(5)); /* need to be in L0 for gen switch */ ret = msm_pcie_prevent_l1(root_pci_dev); if (ret) return ret; if (target_link_speed > current_link_speed) msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed); Loading @@ -6187,9 +6271,7 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, if (target_link_speed < current_link_speed) msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed); out: /* re-enable link L1 */ msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0); msm_pcie_config_l1(pcie_dev, root_pci_dev, true); msm_pcie_allow_l1(root_pci_dev); return ret; } Loading Loading @@ -6500,6 +6582,7 @@ static int __init pcie_init(void) mutex_init(&msm_pcie_dev[i].setup_lock); mutex_init(&msm_pcie_dev[i].clk_lock); mutex_init(&msm_pcie_dev[i].recovery_lock); mutex_init(&msm_pcie_dev[i].aspm_lock); spin_lock_init(&msm_pcie_dev[i].wakeup_lock); spin_lock_init(&msm_pcie_dev[i].irq_lock); msm_pcie_dev[i].drv_ready = false; Loading include/linux/msm_pcie.h +29 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,26 @@ static inline int msm_msi_init(struct device *dev) #ifdef CONFIG_PCI_MSM /** * msm_pcie_allow_l1 - allow PCIe link to re-enter L1 * @pci_dev: client's pci device structure * * This function gives PCIe clients the control to allow the link to re-enter * L1. Should only be used after msm_pcie_prevent_l1 has been called. */ void msm_pcie_allow_l1(struct pci_dev *pci_dev); /** * msm_pcie_prevent_l1 - keeps PCIe link out of L1 * @pci_dev: client's pci device structure * * This function gives PCIe clients the control to exit and prevent the link * from entering L1. * * Return 0 on success, negative value on error */ int msm_pcie_prevent_l1(struct pci_dev *pci_dev); /** * msm_pcie_set_link_bandwidth - updates the number of lanes and speed of PCIe * link. Loading Loading @@ -202,6 +222,15 @@ static inline int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, return -ENODEV; } static inline void msm_pcie_allow_l1(struct pci_dev *pci_dev) { } static inline int msm_pcie_prevent_l1(struct pci_dev *pci_dev) { return -ENODEV; } static inline int msm_pcie_l1ss_timeout_disable(struct pci_dev *pci_dev) { return -ENODEV; Loading Loading
drivers/pci/controller/pci-msm.c +103 −20 Original line number Diff line number Diff line Loading @@ -725,6 +725,8 @@ struct msm_pcie_dev_t { struct mutex recovery_lock; spinlock_t wakeup_lock; spinlock_t irq_lock; struct mutex aspm_lock; int prevent_l1; ulong linkdown_counter; ulong link_turned_on_counter; ulong link_turned_off_counter; Loading Loading @@ -1392,6 +1394,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->wake_counter); PCIE_DBG_FS(dev, "link_check_max_count: %u\n", dev->link_check_max_count); PCIE_DBG_FS(dev, "prevent_l1: %d\n", dev->prevent_l1); PCIE_DBG_FS(dev, "target_link_speed: 0x%x\n", dev->target_link_speed); PCIE_DBG_FS(dev, "link_turned_on_counter: %lu\n", Loading Loading @@ -6051,20 +6055,6 @@ static int msm_pcie_link_retrain(struct msm_pcie_dev_t *pcie_dev, u32 cnt_max = 1000; /* 100ms timeout */ u32 link_status_lbms_mask = PCI_EXP_LNKSTA_LBMS << PCI_EXP_LNKCTL; cnt = 0; /* confirm link is in L0 */ while (((readl_relaxed(pcie_dev->parf + PCIE20_PARF_LTSSM) & MSM_PCIE_LTSSM_MASK)) != MSM_PCIE_LTSSM_L0) { if (unlikely(cnt++ >= cnt_max)) { PCIE_ERR(pcie_dev, "PCIe: RC%d: failed to transition to L0\n", pcie_dev->rc_idx); return -EIO; } usleep_range(100, 105); } /* link retrain */ msm_pcie_config_clear_set_dword(pci_dev, pci_dev->pcie_cap + PCI_EXP_LNKCTL, Loading Loading @@ -6113,6 +6103,99 @@ static int msm_pcie_set_link_width(struct msm_pcie_dev_t *pcie_dev, return 0; } void msm_pcie_allow_l1(struct pci_dev *pci_dev) { struct pci_dev *root_pci_dev; struct msm_pcie_dev_t *pcie_dev; root_pci_dev = pci_find_pcie_root_port(pci_dev); if (!root_pci_dev) return; pcie_dev = PCIE_BUS_PRIV_DATA(root_pci_dev->bus); mutex_lock(&pcie_dev->aspm_lock); if (unlikely(--pcie_dev->prevent_l1 < 0)) PCIE_ERR(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: unbalanced prevent_l1: %d < 0\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), pcie_dev->prevent_l1); if (pcie_dev->prevent_l1) { mutex_unlock(&pcie_dev->aspm_lock); return; } msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0); /* enable L1 */ msm_pcie_write_mask(pcie_dev->dm_core + (root_pci_dev->pcie_cap + PCI_EXP_LNKCTL), 0, PCI_EXP_LNKCTL_ASPM_L1); PCIE_DBG2(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: exit\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); mutex_unlock(&pcie_dev->aspm_lock); } EXPORT_SYMBOL(msm_pcie_allow_l1); int msm_pcie_prevent_l1(struct pci_dev *pci_dev) { struct pci_dev *root_pci_dev; struct msm_pcie_dev_t *pcie_dev; u32 cnt = 0; u32 cnt_max = 1000; /* 100ms timeout */ int ret = 0; root_pci_dev = pci_find_pcie_root_port(pci_dev); if (!root_pci_dev) return -ENODEV; pcie_dev = PCIE_BUS_PRIV_DATA(root_pci_dev->bus); /* disable L1 */ mutex_lock(&pcie_dev->aspm_lock); if (pcie_dev->prevent_l1++) { mutex_unlock(&pcie_dev->aspm_lock); return 0; } msm_pcie_write_mask(pcie_dev->dm_core + (root_pci_dev->pcie_cap + PCI_EXP_LNKCTL), 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) { if (unlikely(cnt++ >= cnt_max)) { PCIE_ERR(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: failed to transition to L0\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); ret = -EIO; goto err; } usleep_range(100, 105); } PCIE_DBG2(pcie_dev, "PCIe: RC%d: %02x:%02x.%01x: exit\n", pcie_dev->rc_idx, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); mutex_unlock(&pcie_dev->aspm_lock); return 0; err: mutex_unlock(&pcie_dev->aspm_lock); msm_pcie_allow_l1(pci_dev); return ret; } EXPORT_SYMBOL(msm_pcie_prevent_l1); int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, u16 target_link_width) { Loading Loading @@ -6162,9 +6245,10 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, PCI_EXP_LNKSTA_CLS, target_link_speed); /* disable link L1. Need to be in L0 for gen switch */ msm_pcie_config_l1(pcie_dev, root_pci_dev, false); msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(5)); /* need to be in L0 for gen switch */ ret = msm_pcie_prevent_l1(root_pci_dev); if (ret) return ret; if (target_link_speed > current_link_speed) msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed); Loading @@ -6187,9 +6271,7 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, if (target_link_speed < current_link_speed) msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed); out: /* re-enable link L1 */ msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0); msm_pcie_config_l1(pcie_dev, root_pci_dev, true); msm_pcie_allow_l1(root_pci_dev); return ret; } Loading Loading @@ -6500,6 +6582,7 @@ static int __init pcie_init(void) mutex_init(&msm_pcie_dev[i].setup_lock); mutex_init(&msm_pcie_dev[i].clk_lock); mutex_init(&msm_pcie_dev[i].recovery_lock); mutex_init(&msm_pcie_dev[i].aspm_lock); spin_lock_init(&msm_pcie_dev[i].wakeup_lock); spin_lock_init(&msm_pcie_dev[i].irq_lock); msm_pcie_dev[i].drv_ready = false; Loading
include/linux/msm_pcie.h +29 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,26 @@ static inline int msm_msi_init(struct device *dev) #ifdef CONFIG_PCI_MSM /** * msm_pcie_allow_l1 - allow PCIe link to re-enter L1 * @pci_dev: client's pci device structure * * This function gives PCIe clients the control to allow the link to re-enter * L1. Should only be used after msm_pcie_prevent_l1 has been called. */ void msm_pcie_allow_l1(struct pci_dev *pci_dev); /** * msm_pcie_prevent_l1 - keeps PCIe link out of L1 * @pci_dev: client's pci device structure * * This function gives PCIe clients the control to exit and prevent the link * from entering L1. * * Return 0 on success, negative value on error */ int msm_pcie_prevent_l1(struct pci_dev *pci_dev); /** * msm_pcie_set_link_bandwidth - updates the number of lanes and speed of PCIe * link. Loading Loading @@ -202,6 +222,15 @@ static inline int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, return -ENODEV; } static inline void msm_pcie_allow_l1(struct pci_dev *pci_dev) { } static inline int msm_pcie_prevent_l1(struct pci_dev *pci_dev) { return -ENODEV; } static inline int msm_pcie_l1ss_timeout_disable(struct pci_dev *pci_dev) { return -ENODEV; Loading