Loading drivers/net/wireless/cnss2/main.h +1 −0 Original line number Diff line number Diff line Loading @@ -427,6 +427,7 @@ struct cnss_plat_data { struct cnss_platform_cap cap; struct pm_qos_request qos_request; struct cnss_device_version device_version; u32 rc_num; unsigned long device_id; enum cnss_driver_status driver_status; u32 recovery_count; Loading drivers/net/wireless/cnss2/pci.c +306 −45 Original line number Diff line number Diff line Loading @@ -371,6 +371,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; Loading Loading @@ -752,8 +978,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; Loading @@ -762,43 +987,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) { Loading Loading @@ -953,7 +1163,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); Loading Loading @@ -983,7 +1193,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); Loading Loading @@ -1040,9 +1250,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); Loading Loading @@ -1475,6 +1683,7 @@ static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, 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 Loading Loading @@ -1508,6 +1717,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) { Loading Loading @@ -2629,6 +2845,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); Loading Loading @@ -2699,6 +2916,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; Loading Loading @@ -2730,6 +2957,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) { Loading Loading @@ -3089,10 +3324,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; Loading Loading @@ -4903,22 +5135,36 @@ static int cnss_mhi_bw_scale(struct mhi_controller *mhi_ctrl, struct mhi_link_info *link_info) { struct cnss_pci_data *pci_priv = mhi_ctrl->priv_data; struct cnss_plat_data *plat_priv = pci_priv->plat_priv; int ret = 0; ret = msm_pcie_set_link_bandwidth(pci_priv->pci_dev, cnss_pr_dbg("Setting link speed:0x%x, width:0x%x\n", link_info->target_link_speed, link_info->target_link_width); /* It has to set target link speed here before setting link bandwidth * when device requests link speed change. This can avoid setting link * bandwidth getting rejected if requested link speed is higher than * current one. */ 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 = cnss_pci_set_link_bandwidth(pci_priv, link_info->target_link_speed, link_info->target_link_width); if (ret) { cnss_pr_err("Failed to set link bandwidth, err = %d\n", ret); return ret; } pci_priv->def_link_speed = link_info->target_link_speed; pci_priv->def_link_width = link_info->target_link_width; cnss_pr_dbg("Setting link speed:0x%x, width:0x%x\n", link_info->target_link_speed, link_info->target_link_width); return 0; } Loading Loading @@ -5444,8 +5690,23 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv) goto out; } plat_priv->rc_num = rc_num; /* Always set initial target PCIe link speed to Gen2 for QCA6490 device * since there may be link issues if it boots up with Gen3 link speed. * Device is able to change it later at any time. It will be rejected * if requested speed is higher than the one specified in PCIe DT. */ if (plat_priv->device_id == QCA6490_DEVICE_ID) { 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); Loading drivers/net/wireless/cnss2/pci.h +5 −1 Original line number Diff line number Diff line /* 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 <linux/iommu.h> #include <linux/mhi.h> #if IS_ENABLED(CONFIG_PCI_MSM) #include <linux/msm_pcie.h> #endif #include <linux/pci.h> #include "main.h" Loading Loading @@ -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; Loading Loading
drivers/net/wireless/cnss2/main.h +1 −0 Original line number Diff line number Diff line Loading @@ -427,6 +427,7 @@ struct cnss_plat_data { struct cnss_platform_cap cap; struct pm_qos_request qos_request; struct cnss_device_version device_version; u32 rc_num; unsigned long device_id; enum cnss_driver_status driver_status; u32 recovery_count; Loading
drivers/net/wireless/cnss2/pci.c +306 −45 Original line number Diff line number Diff line Loading @@ -371,6 +371,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; Loading Loading @@ -752,8 +978,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; Loading @@ -762,43 +987,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) { Loading Loading @@ -953,7 +1163,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); Loading Loading @@ -983,7 +1193,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); Loading Loading @@ -1040,9 +1250,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); Loading Loading @@ -1475,6 +1683,7 @@ static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv, 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 Loading Loading @@ -1508,6 +1717,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) { Loading Loading @@ -2629,6 +2845,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); Loading Loading @@ -2699,6 +2916,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; Loading Loading @@ -2730,6 +2957,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) { Loading Loading @@ -3089,10 +3324,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; Loading Loading @@ -4903,22 +5135,36 @@ static int cnss_mhi_bw_scale(struct mhi_controller *mhi_ctrl, struct mhi_link_info *link_info) { struct cnss_pci_data *pci_priv = mhi_ctrl->priv_data; struct cnss_plat_data *plat_priv = pci_priv->plat_priv; int ret = 0; ret = msm_pcie_set_link_bandwidth(pci_priv->pci_dev, cnss_pr_dbg("Setting link speed:0x%x, width:0x%x\n", link_info->target_link_speed, link_info->target_link_width); /* It has to set target link speed here before setting link bandwidth * when device requests link speed change. This can avoid setting link * bandwidth getting rejected if requested link speed is higher than * current one. */ 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 = cnss_pci_set_link_bandwidth(pci_priv, link_info->target_link_speed, link_info->target_link_width); if (ret) { cnss_pr_err("Failed to set link bandwidth, err = %d\n", ret); return ret; } pci_priv->def_link_speed = link_info->target_link_speed; pci_priv->def_link_width = link_info->target_link_width; cnss_pr_dbg("Setting link speed:0x%x, width:0x%x\n", link_info->target_link_speed, link_info->target_link_width); return 0; } Loading Loading @@ -5444,8 +5690,23 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv) goto out; } plat_priv->rc_num = rc_num; /* Always set initial target PCIe link speed to Gen2 for QCA6490 device * since there may be link issues if it boots up with Gen3 link speed. * Device is able to change it later at any time. It will be rejected * if requested speed is higher than the one specified in PCIe DT. */ if (plat_priv->device_id == QCA6490_DEVICE_ID) { 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); Loading
drivers/net/wireless/cnss2/pci.h +5 −1 Original line number Diff line number Diff line /* 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 <linux/iommu.h> #include <linux/mhi.h> #if IS_ENABLED(CONFIG_PCI_MSM) #include <linux/msm_pcie.h> #endif #include <linux/pci.h> #include "main.h" Loading Loading @@ -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; Loading