From 2dc22bc62d06c8b0e9bcf1b8448fcbc62bed9838 Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Fri, 4 Dec 2020 18:34:50 -0800 Subject: [PATCH] cnss2: Use CONFIG_PCI_MSM to protect MSM PCIe APIs This can ease the complexity to port CNSS2 driver to non-MSM platforms while still be able to maintain the compatibility. Change-Id: I268cdd90c59085b34aa2fe3c3b845d60c4e2a417 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/pci.c | 320 ++++++++++++++++++++++++++----- drivers/net/wireless/cnss2/pci.h | 6 +- 2 files changed, 281 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 593e79642e55..c455a6df3e52 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -370,6 +370,232 @@ static struct cnss_misc_reg wlaon_reg_access_seq[] = { #define PCIE_REG_SIZE ARRAY_SIZE(pcie_reg_access_seq) #define WLAON_REG_SIZE ARRAY_SIZE(wlaon_reg_access_seq) +#if IS_ENABLED(CONFIG_PCI_MSM) +/** + * cnss_pci_enumerate() - Enumerate PCIe endpoints + * @plat_priv: driver platform context pointer + * @rc_num: root complex index that an endpoint connects to + * + * This function shall call corresponding PCIe root complex driver APIs + * to power on root complex and enumerate the endpoint connected to it. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_enumerate(struct cnss_plat_data *plat_priv, int rc_num) +{ + return msm_pcie_enumerate(rc_num); +} + +/** + * cnss_pci_assert_perst() - Assert PCIe PERST GPIO + * @pci_priv: driver PCI bus context pointer + * + * This function shall call corresponding PCIe root complex driver APIs + * to assert PCIe PERST GPIO. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_assert_perst(struct cnss_pci_data *pci_priv) +{ + struct pci_dev *pci_dev = pci_priv->pci_dev; + + return msm_pcie_pm_control(MSM_PCIE_HANDLE_LINKDOWN, + pci_dev->bus->number, pci_dev, NULL, + PM_OPTIONS_DEFAULT); +} + +/** + * cnss_pci_disable_pc() - Disable PCIe link power collapse from RC driver + * @pci_priv: driver PCI bus context pointer + * @vote: value to indicate disable (true) or enable (false) + * + * This function shall call corresponding PCIe root complex driver APIs + * to disable PCIe power collapse. The purpose of this API is to avoid + * root complex driver still controlling PCIe link from callbacks of + * system suspend/resume. Device driver itself should take full control + * of the link in such cases. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_disable_pc(struct cnss_pci_data *pci_priv, bool vote) +{ + struct pci_dev *pci_dev = pci_priv->pci_dev; + + return msm_pcie_pm_control(vote ? MSM_PCIE_DISABLE_PC : + MSM_PCIE_ENABLE_PC, + pci_dev->bus->number, pci_dev, NULL, + PM_OPTIONS_DEFAULT); +} + +/** + * cnss_pci_set_link_bandwidth() - Update number of lanes and speed of + * PCIe link + * @pci_priv: driver PCI bus context pointer + * @link_speed: PCIe link gen speed + * @link_width: number of lanes for PCIe link + * + * This function shall call corresponding PCIe root complex driver APIs + * to update number of lanes and speed of the link. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_set_link_bandwidth(struct cnss_pci_data *pci_priv, + u16 link_speed, u16 link_width) +{ + return msm_pcie_set_link_bandwidth(pci_priv->pci_dev, + link_speed, link_width); +} + +/** + * cnss_pci_set_max_link_speed() - Set the maximum speed PCIe can link up with + * @pci_priv: driver PCI bus context pointer + * @rc_num: root complex index that an endpoint connects to + * @link_speed: PCIe link gen speed + * + * This function shall call corresponding PCIe root complex driver APIs + * to update the maximum speed that PCIe can link up with. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_set_max_link_speed(struct cnss_pci_data *pci_priv, + u32 rc_num, u16 link_speed) +{ + return msm_pcie_set_target_link_speed(rc_num, link_speed); +} + +/** + * _cnss_pci_prevent_l1() - Prevent PCIe L1 and L1 sub-states + * @pci_priv: driver PCI bus context pointer + * + * This function shall call corresponding PCIe root complex driver APIs + * to prevent PCIe link enter L1 and L1 sub-states. The APIs should also + * bring link out of L1 or L1 sub-states if any and avoid synchronization + * issues if any. + * + * Return: 0 for success, negative value for error + */ +static int _cnss_pci_prevent_l1(struct cnss_pci_data *pci_priv) +{ + return msm_pcie_prevent_l1(pci_priv->pci_dev); +} + +/** + * _cnss_pci_allow_l1() - Allow PCIe L1 and L1 sub-states + * @pci_priv: driver PCI bus context pointer + * + * This function shall call corresponding PCIe root complex driver APIs + * to allow PCIe link enter L1 and L1 sub-states. The APIs should avoid + * synchronization issues if any. + * + * Return: 0 for success, negative value for error + */ +static void _cnss_pci_allow_l1(struct cnss_pci_data *pci_priv) +{ + msm_pcie_allow_l1(pci_priv->pci_dev); +} + +/** + * cnss_pci_set_link_up() - Power on or resume PCIe link + * @pci_priv: driver PCI bus context pointer + * + * This function shall call corresponding PCIe root complex driver APIs + * to Power on or resume PCIe link. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_set_link_up(struct cnss_pci_data *pci_priv) +{ + struct pci_dev *pci_dev = pci_priv->pci_dev; + enum msm_pcie_pm_opt pm_ops = MSM_PCIE_RESUME; + u32 pm_options = PM_OPTIONS_DEFAULT; + int ret; + + ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev, + NULL, pm_options); + if (ret) + cnss_pr_err("Failed to resume PCI link with default option, err = %d\n", + ret); + + return ret; +} + +/** + * cnss_pci_set_link_down() - Power off or suspend PCIe link + * @pci_priv: driver PCI bus context pointer + * + * This function shall call corresponding PCIe root complex driver APIs + * to power off or suspend PCIe link. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_set_link_down(struct cnss_pci_data *pci_priv) +{ + struct pci_dev *pci_dev = pci_priv->pci_dev; + enum msm_pcie_pm_opt pm_ops; + u32 pm_options = PM_OPTIONS_DEFAULT; + int ret; + + if (pci_priv->drv_connected_last) { + cnss_pr_vdbg("Use PCIe DRV suspend\n"); + pm_ops = MSM_PCIE_DRV_SUSPEND; + } else { + pm_ops = MSM_PCIE_SUSPEND; + } + + ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev, + NULL, pm_options); + if (ret) + cnss_pr_err("Failed to suspend PCI link with default option, err = %d\n", + ret); + + return ret; +} +#else +static int cnss_pci_enumerate(struct cnss_plat_data *plat_priv, int rc_num) +{ + return -EOPNOTSUPP; +} + +static int cnss_pci_assert_perst(struct cnss_pci_data *pci_priv) +{ + return -EOPNOTSUPP; +} + +static int cnss_pci_disable_pc(struct cnss_pci_data *pci_priv, bool vote) +{ + return 0; +} + +static int cnss_pci_set_link_bandwidth(struct cnss_pci_data *pci_priv, + u16 link_speed, u16 link_width) +{ + return 0; +} + +static int cnss_pci_set_max_link_speed(struct cnss_pci_data *pci_priv, + u32 rc_num, u16 link_speed) +{ + return 0; +} + +static int _cnss_pci_prevent_l1(struct cnss_pci_data *pci_priv) +{ + return 0; +} + +static void _cnss_pci_allow_l1(struct cnss_pci_data *pci_priv) {} + +static int cnss_pci_set_link_up(struct cnss_pci_data *pci_priv) +{ + return 0; +} + +static int cnss_pci_set_link_down(struct cnss_pci_data *pci_priv) +{ + return 0; +} +#endif /* CONFIG_PCI_MSM */ + int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv) { u16 device_id; @@ -738,8 +964,7 @@ static int cnss_set_pci_link_status(struct cnss_pci_data *pci_priv, return -EINVAL; } - ret = msm_pcie_set_link_bandwidth(pci_priv->pci_dev, - link_speed, link_width); + ret = cnss_pci_set_link_bandwidth(pci_priv, link_speed, link_width); if (!ret) pci_priv->cur_link_speed = link_speed; @@ -748,43 +973,28 @@ static int cnss_set_pci_link_status(struct cnss_pci_data *pci_priv, static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up) { - int ret = 0; - struct pci_dev *pci_dev = pci_priv->pci_dev; - enum msm_pcie_pm_opt pm_ops; - int retry = 0; - u32 pm_options = PM_OPTIONS_DEFAULT; + int ret = 0, retry = 0; cnss_pr_vdbg("%s PCI link\n", link_up ? "Resuming" : "Suspending"); if (link_up) { - pm_ops = MSM_PCIE_RESUME; - } else { - if (pci_priv->drv_connected_last) { - cnss_pr_vdbg("Use PCIe DRV suspend\n"); - pm_ops = MSM_PCIE_DRV_SUSPEND; - /* Since DRV suspend cannot be done in Gen 3, set it to - * Gen 2 if current link speed is larger than Gen 2. - */ - if (pci_priv->cur_link_speed > - PCI_EXP_LNKSTA_CLS_5_0GB) - cnss_set_pci_link_status(pci_priv, PCI_GEN2); - } else { - pm_ops = MSM_PCIE_SUSPEND; - } - } - retry: - ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev, - NULL, pm_options); - if (ret) { - cnss_pr_err("Failed to %s PCI link with default option, err = %d\n", - link_up ? "resume" : "suspend", ret); - if (link_up && retry++ < LINK_TRAINING_RETRY_MAX_TIMES) { + ret = cnss_pci_set_link_up(pci_priv); + if (ret && retry++ < LINK_TRAINING_RETRY_MAX_TIMES) { cnss_pr_dbg("Retry PCI link training #%d\n", retry); if (pci_priv->pci_link_down_ind) msleep(LINK_TRAINING_RETRY_DELAY_MS * retry); goto retry; } + } else { + /* Since DRV suspend cannot be done in Gen 3, set it to + * Gen 2 if current link speed is larger than Gen 2. + */ + if (pci_priv->drv_connected_last && + pci_priv->cur_link_speed > PCI_EXP_LNKSTA_CLS_5_0GB) + cnss_set_pci_link_status(pci_priv, PCI_GEN2); + + ret = cnss_pci_set_link_down(pci_priv); } if (pci_priv->drv_connected_last) { @@ -939,7 +1149,7 @@ int cnss_pci_prevent_l1(struct device *dev) return -EIO; } - ret = msm_pcie_prevent_l1(pci_dev); + ret = _cnss_pci_prevent_l1(pci_priv); if (ret == -EIO) { cnss_pr_err("Failed to prevent PCIe L1, considered as link down\n"); cnss_pci_link_down(dev); @@ -969,7 +1179,7 @@ void cnss_pci_allow_l1(struct device *dev) return; } - msm_pcie_allow_l1(pci_dev); + _cnss_pci_allow_l1(pci_priv); } EXPORT_SYMBOL(cnss_pci_allow_l1); @@ -1026,9 +1236,7 @@ int cnss_pci_link_down(struct device *dev) cnss_pr_err("PCI link down is detected by drivers\n"); - ret = msm_pcie_pm_control(MSM_PCIE_HANDLE_LINKDOWN, - pci_dev->bus->number, pci_dev, NULL, - PM_OPTIONS_DEFAULT); + ret = cnss_pci_assert_perst(pci_priv); if (ret) cnss_pci_handle_linkdown(pci_priv); @@ -1461,6 +1669,7 @@ out: return ret; } +#if IS_ENABLED(CONFIG_PCI_MSM) /** * cnss_wlan_adsp_pc_enable: Control ADSP power collapse setup * @dev: Platform driver pci private data structure @@ -1494,6 +1703,13 @@ static int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv, cnss_pr_dbg("%s ADSP power collapse\n", control ? "Enable" : "Disable"); return 0; } +#else +static int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv, + bool control) +{ + return 0; +} +#endif int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv) { @@ -2615,6 +2831,7 @@ int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv) return 0; } +#if IS_ENABLED(CONFIG_PCI_MSM) static bool cnss_pci_is_drv_supported(struct cnss_pci_data *pci_priv) { struct pci_dev *root_port = pci_find_pcie_root_port(pci_priv->pci_dev); @@ -2691,6 +2908,16 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify) } } +/** + * cnss_reg_pci_event() - Register for PCIe events + * @pci_priv: driver PCI bus context pointer + * + * This function shall call corresponding PCIe root complex driver APIs + * to register for PCIe events like link down or WAKE GPIO toggling etc. + * The events should be based on PCIe root complex driver's capability. + * + * Return: 0 for success, negative value for error + */ static int cnss_reg_pci_event(struct cnss_pci_data *pci_priv) { int ret = 0; @@ -2722,6 +2949,14 @@ static void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv) { msm_pcie_deregister_event(&pci_priv->msm_pci_event); } +#else +static int cnss_reg_pci_event(struct cnss_pci_data *pci_priv) +{ + return 0; +} + +static void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv) {} +#endif static int cnss_pci_suspend_driver(struct cnss_pci_data *pci_priv) { @@ -3081,10 +3316,7 @@ int cnss_wlan_pm_control(struct device *dev, bool vote) if (!pci_priv) return -ENODEV; - ret = msm_pcie_pm_control(vote ? MSM_PCIE_DISABLE_PC : - MSM_PCIE_ENABLE_PC, - pci_dev->bus->number, pci_dev, - NULL, PM_OPTIONS_DEFAULT); + ret = cnss_pci_disable_pc(pci_priv, vote); if (ret) return ret; @@ -4907,13 +5139,13 @@ static int cnss_mhi_bw_scale(struct mhi_controller *mhi_ctrl, * bandwidth getting rejected if requested link speed is higher than * current one. */ - ret = msm_pcie_set_target_link_speed(plat_priv->rc_num, - link_info->target_link_speed); + ret = cnss_pci_set_max_link_speed(pci_priv, plat_priv->rc_num, + link_info->target_link_speed); if (ret) cnss_pr_err("Failed to set target link speed to 0x%x, err = %d\n", link_info->target_link_speed, ret); - ret = msm_pcie_set_link_bandwidth(pci_priv->pci_dev, + ret = cnss_pci_set_link_bandwidth(pci_priv, link_info->target_link_speed, link_info->target_link_width); @@ -5295,15 +5527,15 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv) * if requested speed is higher than the one specified in PCIe DT. */ if (plat_priv->device_id == QCA6490_DEVICE_ID) { - ret = msm_pcie_set_target_link_speed(rc_num, - PCI_EXP_LNKSTA_CLS_5_0GB); + ret = cnss_pci_set_max_link_speed(plat_priv->bus_priv, rc_num, + PCI_EXP_LNKSTA_CLS_5_0GB); if (ret) cnss_pr_err("Failed to set target PCIe link speed to Gen2, err = %d\n", ret); } retry: - ret = msm_pcie_enumerate(rc_num); + ret = cnss_pci_enumerate(plat_priv, rc_num); if (ret) { cnss_pr_err("Failed to enable PCIe RC%x, err = %d\n", rc_num, ret); diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index e44e1b298d7e..f9daf2737a22 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -1,12 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _CNSS_PCI_H #define _CNSS_PCI_H #include #include +#if IS_ENABLED(CONFIG_PCI_MSM) #include +#endif #include #include "main.h" @@ -86,7 +88,9 @@ struct cnss_pci_data { u8 pci_link_down_ind; struct pci_saved_state *saved_state; struct pci_saved_state *default_state; +#if IS_ENABLED(CONFIG_PCI_MSM) struct msm_pcie_register_event msm_pci_event; +#endif struct cnss_pm_stats pm_stats; atomic_t auto_suspended; atomic_t drv_connected;