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

Commit 2dc22bc6 authored by Yue Ma's avatar Yue Ma Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarYue Ma <yuem@codeaurora.org>
parent dc0ecaca
Loading
Loading
Loading
Loading
+276 −44
Original line number Diff line number Diff line
@@ -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 @@ 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
@@ -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,
	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,7 +5527,7 @@ 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,
		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",
@@ -5303,7 +5535,7 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv)
	}

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;