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

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

Merge "cnss2: Add PCI DRV support"

parents bdadaa0f f28455cb
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -601,6 +601,9 @@ static int cnss_show_quirks_state(struct seq_file *s,
		case ENABLE_DAEMON_SUPPORT:
			seq_puts(s, "DAEMON_SUPPORT");
			continue;
		case DISABLE_DRV:
			seq_puts(s, "DISABLE_DRV");
			continue;
		}

		seq_printf(s, "UNKNOWN-%d", i);
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
#define FW_ASSERT_TIMEOUT		5000
#define CNSS_EVENT_PENDING		2989

#define CNSS_QUIRKS_DEFAULT		0
#define CNSS_QUIRKS_DEFAULT		512
#ifdef CONFIG_CNSS_EMULATION
#define CNSS_MHI_TIMEOUT_DEFAULT	90000
#else
+1 −0
Original line number Diff line number Diff line
@@ -222,6 +222,7 @@ enum cnss_debug_quirks {
	ENABLE_PCI_LINK_DOWN_PANIC,
	FBC_BYPASS,
	ENABLE_DAEMON_SUPPORT,
	DISABLE_DRV,
};

enum cnss_bdf_type {
+161 −16
Original line number Diff line number Diff line
@@ -341,25 +341,91 @@ static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save)
	return 0;
}

static int cnss_pci_get_link_status(struct cnss_pci_data *pci_priv)
{
	u16 link_status;
	int ret;

	ret = pcie_capability_read_word(pci_priv->pci_dev, PCI_EXP_LNKSTA,
					&link_status);
	if (ret)
		return ret;

	cnss_pr_dbg("Get PCI link status register: %u\n", link_status);

	pci_priv->def_link_speed = link_status & PCI_EXP_LNKSTA_CLS;
	pci_priv->def_link_width =
		(link_status & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;

	cnss_pr_dbg("Default PCI link speed is 0x%x, link width is 0x%x\n",
		    pci_priv->def_link_speed, pci_priv->def_link_width);

	return 0;
}

static int cnss_set_pci_link_status(struct cnss_pci_data *pci_priv,
				    enum pci_link_status status)
{
	u16 link_speed, link_width;

	cnss_pr_dbg("Set PCI link status to: %u\n", status);

	switch (status) {
	case PCI_GEN1:
		link_speed = PCI_EXP_LNKSTA_CLS_2_5GB;
		link_width = PCI_EXP_LNKSTA_NLW_X1 >> PCI_EXP_LNKSTA_NLW_SHIFT;
		break;
	case PCI_GEN2:
		link_speed = PCI_EXP_LNKSTA_CLS_5_0GB;
		link_width = PCI_EXP_LNKSTA_NLW_X1 >> PCI_EXP_LNKSTA_NLW_SHIFT;
		break;
	case PCI_DEF:
		link_speed = pci_priv->def_link_speed;
		link_width = pci_priv->def_link_width;
		if (!link_speed && !link_width) {
			cnss_pr_err("PCI link speed or width is not valid\n");
			return -EINVAL;
		}
		break;
	default:
		cnss_pr_err("Unknown PCI link status config: %u\n", status);
		return -EINVAL;
	}

	return msm_pcie_set_link_bandwidth(pci_priv->pci_dev,
					   link_speed, link_width);
}

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;

	cnss_pr_dbg("%s PCI link\n", link_up ? "Resuming" : "Suspending");

	ret = msm_pcie_pm_control(link_up ? MSM_PCIE_RESUME :
				  MSM_PCIE_SUSPEND,
				  pci_dev->bus->number,
				  pci_dev, NULL,
				  PM_OPTIONS_DEFAULT);
	if (ret) {
	if (link_up) {
		pm_ops = MSM_PCIE_RESUME;
	} else {
		if (pci_priv->drv_connected_last) {
			cnss_pr_dbg("Use PCIe DRV suspend\n");
			pm_ops = MSM_PCIE_DRV_SUSPEND;
			cnss_set_pci_link_status(pci_priv, PCI_GEN1);
		} else {
			pm_ops = MSM_PCIE_SUSPEND;
		}
	}

	ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev,
				  NULL, PM_OPTIONS_DEFAULT);
	if (ret)
		cnss_pr_err("Failed to %s PCI link with default option, err = %d\n",
			    link_up ? "resume" : "suspend", ret);
		return ret;
	}

	return 0;
	if ((link_up || (!link_up && ret)) && pci_priv->drv_connected_last)
		cnss_set_pci_link_status(pci_priv, PCI_DEF);

	return ret;
}

int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv)
@@ -1279,6 +1345,22 @@ int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv)
	return 0;
}

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);
	struct device_node *root_of_node = root_port->dev.of_node;
	bool drv_supported = false;

	if (root_of_node->parent)
		drv_supported = of_property_read_bool(root_of_node->parent,
						      "qcom,drv-supported");

	cnss_pr_dbg("PCIe DRV is %s\n",
		    drv_supported ? "supported" : "not supported");

	return drv_supported;
}

static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
{
	unsigned long flags;
@@ -1325,6 +1407,14 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
			cnss_pci_pm_request_resume(pci_priv);
		}
		break;
	case MSM_PCIE_EVENT_DRV_CONNECT:
		cnss_pr_dbg("DRV subsystem is connected\n");
		cnss_pci_set_drv_connected(pci_priv, 1);
		break;
	case MSM_PCIE_EVENT_DRV_DISCONNECT:
		cnss_pr_dbg("DRV subsystem is disconnected\n");
		cnss_pci_set_drv_connected(pci_priv, 0);
		break;
	default:
		cnss_pr_err("Received invalid PCI event: %d\n", notify->event);
	}
@@ -1338,6 +1428,12 @@ static int cnss_reg_pci_event(struct cnss_pci_data *pci_priv)
	pci_event = &pci_priv->msm_pci_event;
	pci_event->events = MSM_PCIE_EVENT_LINKDOWN |
		MSM_PCIE_EVENT_WAKEUP;

	if (cnss_pci_is_drv_supported(pci_priv))
		pci_event->events = pci_event->events |
			MSM_PCIE_EVENT_DRV_CONNECT |
			MSM_PCIE_EVENT_DRV_DISCONNECT;

	pci_event->user = pci_priv->pci_dev;
	pci_event->mode = MSM_PCIE_TRIGGER_CALLBACK;
	pci_event->callback = cnss_pci_event_cb;
@@ -1361,6 +1457,7 @@ static int cnss_pci_suspend(struct device *dev)
	int ret = 0;
	struct pci_dev *pci_dev = to_pci_dev(dev);
	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
	struct cnss_plat_data *plat_priv;
	struct cnss_wlan_driver *driver_ops;

	pm_message_t state = { .event = PM_EVENT_SUSPEND };
@@ -1368,6 +1465,14 @@ static int cnss_pci_suspend(struct device *dev)
	if (!pci_priv)
		goto out;

	plat_priv = pci_priv->plat_priv;
	if (!plat_priv)
		goto out;

	if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks))
		pci_priv->drv_connected_last =
			cnss_pci_get_drv_connected(pci_priv);

	driver_ops = pci_priv->driver_ops;
	if (driver_ops && driver_ops->suspend) {
		ret = driver_ops->suspend(pci_dev, state);
@@ -1385,16 +1490,18 @@ static int cnss_pci_suspend(struct device *dev)
			goto resume_driver;
		}

		if (pci_priv->drv_connected_last)
			goto skip_disable_pci;

		pci_clear_master(pci_dev);
		cnss_set_pci_config_space(pci_priv,
					  SAVE_PCI_CONFIG_SPACE);
		cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
		pci_disable_device(pci_dev);

		ret = pci_set_power_state(pci_dev, PCI_D3hot);
		if (ret)
			cnss_pr_err("Failed to set D3Hot, err = %d\n",
				    ret);
			cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);

skip_disable_pci:
		if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
			ret = -EAGAIN;
			goto resume_mhi;
@@ -1416,6 +1523,7 @@ static int cnss_pci_suspend(struct device *dev)
resume_driver:
	if (driver_ops && driver_ops->resume)
		driver_ops->resume(pci_dev);
	pci_priv->drv_connected_last = 0;
out:
	return ret;
}
@@ -1443,6 +1551,9 @@ static int cnss_pci_resume(struct device *dev)
		}
		pci_priv->pci_link_state = PCI_LINK_UP;

		if (pci_priv->drv_connected_last)
			goto skip_enable_pci;

		ret = pci_enable_device(pci_dev);
		if (ret)
			cnss_pr_err("Failed to enable PCI device, err = %d\n",
@@ -1451,8 +1562,9 @@ static int cnss_pci_resume(struct device *dev)
		if (pci_priv->saved_state)
			cnss_set_pci_config_space(pci_priv,
						  RESTORE_PCI_CONFIG_SPACE);

		pci_set_master(pci_dev);

skip_enable_pci:
		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
	}

@@ -1464,6 +1576,8 @@ static int cnss_pci_resume(struct device *dev)
				    ret);
	}

	pci_priv->drv_connected_last = 0;

	return 0;

out:
@@ -1512,11 +1626,16 @@ static int cnss_pci_runtime_suspend(struct device *dev)
	int ret = 0;
	struct pci_dev *pci_dev = to_pci_dev(dev);
	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
	struct cnss_plat_data *plat_priv;
	struct cnss_wlan_driver *driver_ops;

	if (!pci_priv)
		return -EAGAIN;

	plat_priv = pci_priv->plat_priv;
	if (!plat_priv)
		return -EAGAIN;

	if (pci_priv->pci_link_down_ind) {
		cnss_pr_dbg("PCI link down recovery is in progress!\n");
		return -EAGAIN;
@@ -1524,6 +1643,10 @@ static int cnss_pci_runtime_suspend(struct device *dev)

	cnss_pr_dbg("Runtime suspend start\n");

	if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks))
		pci_priv->drv_connected_last =
			cnss_pci_get_drv_connected(pci_priv);

	driver_ops = pci_priv->driver_ops;
	if (driver_ops && driver_ops->runtime_ops &&
	    driver_ops->runtime_ops->runtime_suspend)
@@ -1531,6 +1654,9 @@ static int cnss_pci_runtime_suspend(struct device *dev)
	else
		ret = cnss_auto_suspend(dev);

	if (ret)
		pci_priv->drv_connected_last = 0;

	cnss_pr_info("Runtime suspend status: %d\n", ret);

	return ret;
@@ -1560,6 +1686,9 @@ static int cnss_pci_runtime_resume(struct device *dev)
	else
		ret = cnss_auto_resume(dev);

	if (!ret)
		pci_priv->drv_connected_last = 0;

	cnss_pr_info("Runtime resume status: %d\n", ret);

	return ret;
@@ -1707,6 +1836,9 @@ int cnss_auto_suspend(struct device *dev)
			goto out;
		}

		if (pci_priv->drv_connected_last)
			goto skip_disable_pci;

		pci_clear_master(pci_dev);
		cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
		pci_disable_device(pci_dev);
@@ -1715,6 +1847,7 @@ int cnss_auto_suspend(struct device *dev)
		if (ret)
			cnss_pr_err("Failed to set D3Hot, err =  %d\n", ret);

skip_disable_pci:
		if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
			ret = -EAGAIN;
			goto resume_mhi;
@@ -1765,6 +1898,9 @@ int cnss_auto_resume(struct device *dev)
		}
		pci_priv->pci_link_state = PCI_LINK_UP;

		if (pci_priv->drv_connected_last)
			goto skip_enable_pci;

		ret = pci_enable_device(pci_dev);
		if (ret)
			cnss_pr_err("Failed to enable PCI device, err = %d\n",
@@ -1772,6 +1908,8 @@ int cnss_auto_resume(struct device *dev)

		cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
		pci_set_master(pci_dev);

skip_enable_pci:
		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
	}

@@ -3054,9 +3192,15 @@ int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
		ret = 0;
		break;
	case CNSS_MHI_SUSPEND:
		if (pci_priv->drv_connected_last)
			ret = mhi_pm_fast_suspend(pci_priv->mhi_ctrl, true);
		else
			ret = mhi_pm_suspend(pci_priv->mhi_ctrl);
		break;
	case CNSS_MHI_RESUME:
		if (pci_priv->drv_connected_last)
			ret = mhi_pm_fast_resume(pci_priv->mhi_ctrl, true);
		else
			ret = mhi_pm_resume(pci_priv->mhi_ctrl);
		break;
	case CNSS_MHI_TRIGGER_RDDM:
@@ -3219,6 +3363,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
			cnss_pci_disable_msi(pci_priv);
			goto disable_bus;
		}
		cnss_pci_get_link_status(pci_priv);
		if (EMULATION_HW)
			break;
		ret = cnss_suspend_pci_link(pci_priv);
+23 −0
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@ enum cnss_mhi_state {
	CNSS_MHI_RDDM_DONE,
};

enum pci_link_status {
	PCI_GEN1,
	PCI_GEN2,
	PCI_DEF,
};

struct cnss_msi_user {
	char *name;
	int num_vectors;
@@ -60,7 +66,10 @@ struct cnss_pci_data {
	struct pci_saved_state *default_state;
	struct msm_pcie_register_event msm_pci_event;
	atomic_t auto_suspended;
	atomic_t drv_connected;
	u8 drv_connected_last;
	u16 def_link_speed;
	u16 def_link_width;
	u8 monitor_wake_intr;
	struct dma_iommu_mapping smmu_mapping;
	struct iommu_domain *iommu_domain;
@@ -126,6 +135,20 @@ static inline int cnss_pci_get_auto_suspended(void *bus_priv)
	return atomic_read(&pci_priv->auto_suspended);
}

static inline void cnss_pci_set_drv_connected(void *bus_priv, int val)
{
	struct cnss_pci_data *pci_priv = bus_priv;

	atomic_set(&pci_priv->drv_connected, val);
}

static inline int cnss_pci_get_drv_connected(void *bus_priv)
{
	struct cnss_pci_data *pci_priv = bus_priv;

	return atomic_read(&pci_priv->drv_connected);
}

int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv);
int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
int cnss_pci_init(struct cnss_plat_data *plat_priv);