mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "cnss2: Expose APIs to prevent and allow PCIe L1 state"
This commit is contained in:
commit
eeea05d3fe
4 changed files with 151 additions and 21 deletions
|
|
@ -808,6 +808,22 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int cnss_pci_prevent_l1(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
|
||||
return msm_pcie_prevent_l1(pci_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_pci_prevent_l1);
|
||||
|
||||
void cnss_pci_allow_l1(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
|
||||
msm_pcie_allow_l1(pci_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_pci_allow_l1);
|
||||
|
||||
int cnss_pci_link_down(struct device *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
|
|||
|
|
@ -718,6 +718,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;
|
||||
|
|
@ -1321,6 +1323,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",
|
||||
|
|
@ -5997,20 +6001,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,
|
||||
|
|
@ -6059,6 +6049,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)
|
||||
{
|
||||
|
|
@ -6108,9 +6191,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);
|
||||
|
|
@ -6133,9 +6217,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;
|
||||
}
|
||||
|
|
@ -6444,6 +6526,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;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,26 @@ int msm_msi_init(struct device *dev);
|
|||
|
||||
#if IS_ENABLED(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.
|
||||
|
|
@ -195,6 +215,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;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */
|
||||
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */
|
||||
|
||||
#ifndef _NET_CNSS2_H
|
||||
#define _NET_CNSS2_H
|
||||
|
|
@ -158,6 +158,8 @@ enum cnss_recovery_reason {
|
|||
extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
|
||||
extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
|
||||
extern void cnss_device_crashed(struct device *dev);
|
||||
extern int cnss_pci_prevent_l1(struct device *dev);
|
||||
extern void cnss_pci_allow_l1(struct device *dev);
|
||||
extern int cnss_pci_link_down(struct device *dev);
|
||||
extern int cnss_pci_is_device_down(struct device *dev);
|
||||
extern void cnss_schedule_recovery(struct device *dev,
|
||||
|
|
|
|||
Loading…
Reference in a new issue