Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14507f61 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cnss2: Use CONFIG_PCI_MSM to protect MSM PCIe APIs"

parents 0667a1b5 2dc22bc6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+306 −45
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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) {
@@ -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);
@@ -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);

@@ -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);

@@ -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
@@ -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)
{
@@ -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);
@@ -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;
@@ -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)
{
@@ -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;

@@ -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;
}

@@ -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);
+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"
@@ -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;