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

Commit 31abb40d authored by Tony Truong's avatar Tony Truong Committed by Gerrit - the friendly Code Review server
Browse files

msm: pcie: add new DRV commands for APPS to control PCIe L1ss sleep



Add support to synchronize PCIe L1ss sleep state between APPS
and DRV subsystem. This will remove any ambiguity of PCIe link
state for APPS when trying to enable/disable DRV.

Change-Id: Idb27a631a6eca3aa32a372e2e30235ef0ca10bf4
Signed-off-by: default avatarTony Truong <truong@codeaurora.org>
parent a65504bf
Loading
Loading
Loading
Loading
+86 −77
Original line number Diff line number Diff line
@@ -575,6 +575,8 @@ struct msm_pcie_device_info {
enum msm_pcie_drv_cmds {
	MSM_PCIE_DRV_CMD_ENABLE = 0xc0000000,
	MSM_PCIE_DRV_CMD_DISABLE = 0xc0000001,
	MSM_PCIE_DRV_CMD_ENABLE_L1SS_SLEEP = 0xc0000005,
	MSM_PCIE_DRV_CMD_DISABLE_L1SS_SLEEP = 0xc0000006,
};

/* DRV IPC message type */
@@ -610,6 +612,8 @@ struct msm_pcie_drv_info {
	bool ep_connected; /* drv supports only one endpoint (no switch) */
	struct msm_pcie_drv_msg drv_enable; /* hand off payload */
	struct msm_pcie_drv_msg drv_disable; /* payload to request back */
	struct msm_pcie_drv_msg drv_enable_l1ss_sleep; /* enable l1ss sleep */
	struct msm_pcie_drv_msg drv_disable_l1ss_sleep; /* disable l1ss sleep */
	int dev_id;
	u16 seq;
	u16 reply_seq;
@@ -5548,13 +5552,26 @@ static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev)
	pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev);
}

static void msm_pcie_setup_drv_msg(struct msm_pcie_drv_msg *msg, u32 dev_id,
				enum msm_pcie_drv_cmds cmd)
{
	struct msm_pcie_drv_tre *pkt = &msg->pkt;
	struct msm_pcie_drv_header *hdr = &msg->hdr;

	hdr->major_ver = MSM_PCIE_DRV_MAJOR_VERSION;
	hdr->minor_ver = MSM_PCIE_DRV_MINOR_VERSION;
	hdr->msg_id = MSM_PCIE_DRV_MSG_ID_CMD;
	hdr->payload_size = sizeof(*pkt);
	hdr->dev_id = dev_id;

	pkt->dword[0] = cmd;
	pkt->dword[1] = hdr->dev_id;
}

static int msm_pcie_setup_drv(struct msm_pcie_dev_t *pcie_dev,
			 struct device_node *of_node)
{
	struct msm_pcie_drv_info *drv_info;
	struct msm_pcie_drv_msg *msg;
	struct msm_pcie_drv_tre *pkt;
	struct msm_pcie_drv_header *hdr;
	int ret;

	drv_info = devm_kzalloc(&pcie_dev->pdev->dev, sizeof(*drv_info),
@@ -5572,31 +5589,21 @@ static int msm_pcie_setup_drv(struct msm_pcie_dev_t *pcie_dev,

	drv_info->dev_id = pcie_dev->rc_idx;

	/* cache frequent command for communication */
	msg = &drv_info->drv_enable;
	pkt = &msg->pkt;
	hdr = &msg->hdr;
	hdr->major_ver = MSM_PCIE_DRV_MAJOR_VERSION;
	hdr->minor_ver = MSM_PCIE_DRV_MINOR_VERSION;
	hdr->msg_id = MSM_PCIE_DRV_MSG_ID_CMD;
	hdr->payload_size = sizeof(*pkt);
	hdr->dev_id = drv_info->dev_id;
	msm_pcie_setup_drv_msg(&drv_info->drv_enable, drv_info->dev_id,
				MSM_PCIE_DRV_CMD_ENABLE);

	pkt->dword[0] = MSM_PCIE_DRV_CMD_ENABLE;
	pkt->dword[1] = hdr->dev_id;
	pkt->dword[2] = drv_info->l1ss_timeout_us / 1000;
	msm_pcie_setup_drv_msg(&drv_info->drv_disable, drv_info->dev_id,
				MSM_PCIE_DRV_CMD_DISABLE);

	msg = &drv_info->drv_disable;
	pkt = &msg->pkt;
	hdr = &msg->hdr;
	hdr->major_ver = MSM_PCIE_DRV_MAJOR_VERSION;
	hdr->minor_ver = MSM_PCIE_DRV_MINOR_VERSION;
	hdr->msg_id = MSM_PCIE_DRV_MSG_ID_CMD;
	hdr->payload_size = sizeof(*pkt);
	hdr->dev_id = drv_info->dev_id;
	msm_pcie_setup_drv_msg(&drv_info->drv_enable_l1ss_sleep,
				drv_info->dev_id,
				MSM_PCIE_DRV_CMD_ENABLE_L1SS_SLEEP);
	drv_info->drv_enable_l1ss_sleep.pkt.dword[2] =
					drv_info->l1ss_timeout_us / 1000;

	pkt->dword[0] = MSM_PCIE_DRV_CMD_DISABLE;
	pkt->dword[1] = hdr->dev_id;
	msm_pcie_setup_drv_msg(&drv_info->drv_disable_l1ss_sleep,
				drv_info->dev_id,
				MSM_PCIE_DRV_CMD_DISABLE_L1SS_SLEEP);

	init_completion(&drv_info->completion);
	drv_info->timeout_ms = IPC_TIMEOUT_MS;
@@ -6825,11 +6832,50 @@ static void msm_pcie_fixup_resume_early(struct pci_dev *dev)
DECLARE_PCI_FIXUP_RESUME_EARLY(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
				 msm_pcie_fixup_resume_early);

static int msm_pcie_drv_send_rpmsg(struct msm_pcie_dev_t *pcie_dev,
				struct rpmsg_device *rpdev,
				struct msm_pcie_drv_msg *msg)
{
	struct msm_pcie_drv_info *drv_info = pcie_dev->drv_info;
	int ret;

	reinit_completion(&drv_info->completion);

	drv_info->reply_seq = drv_info->seq++;
	msg->hdr.seq = drv_info->reply_seq;

	if (unlikely(drv_info->seq == MSM_PCIE_DRV_SEQ_RESV))
		drv_info->seq = 0;

	PCIE_DBG(pcie_dev, "PCIe: RC%d: DRV: sending rpmsg: command: 0x%x\n",
		pcie_dev->rc_idx, msg->pkt.dword[0]);

	ret = rpmsg_trysend(rpdev->ept, msg, sizeof(*msg));
	if (ret) {
		PCIE_ERR(pcie_dev, "PCIe: RC%d: DRV: failed to send rpmsg\n",
			pcie_dev->rc_idx);
		return ret;
	}

	ret = wait_for_completion_timeout(&drv_info->completion,
					msecs_to_jiffies(drv_info->timeout_ms));
	if (!ret) {
		PCIE_ERR(pcie_dev,
			"PCIe: RC%d: DRV: completion timeout for rpmsg\n",
			pcie_dev->rc_idx);
		return -ETIMEDOUT;
	}

	PCIE_DBG(pcie_dev, "PCIe: RC%d: DRV: rpmsg successfully sent\n",
		pcie_dev->rc_idx);

	return 0;
}

static int msm_pcie_drv_resume(struct msm_pcie_dev_t *pcie_dev)
{
	struct rpmsg_device *rpdev = pcie_drv.rpdev;
	struct msm_pcie_drv_info *drv_info = pcie_dev->drv_info;
	struct msm_pcie_drv_msg *drv_disable = &drv_info->drv_disable;
	struct msm_pcie_clk_info_t *clk_info;
	u32 current_link_speed;
	int ret, i;
@@ -6837,6 +6883,11 @@ static int msm_pcie_drv_resume(struct msm_pcie_dev_t *pcie_dev)
	mutex_lock(&pcie_dev->recovery_lock);
	mutex_lock(&pcie_dev->setup_lock);

	/* if rpdev is NULL then DRV subsystem is powered down */
	if (rpdev)
		msm_pcie_drv_send_rpmsg(pcie_dev, rpdev,
					&drv_info->drv_disable_l1ss_sleep);

	msm_pcie_vreg_init(pcie_dev);

	regulator_enable(pcie_dev->gdsc);
@@ -6861,30 +6912,9 @@ static int msm_pcie_drv_resume(struct msm_pcie_dev_t *pcie_dev)
			clk_prepare_enable(clk_info->hdl);

	/* if rpdev is NULL then DRV subsystem is powered down */
	if (rpdev) {
		reinit_completion(&drv_info->completion);

		drv_info->reply_seq = drv_info->seq++;
		drv_disable->hdr.seq = drv_info->reply_seq;

		if (unlikely(drv_info->seq == MSM_PCIE_DRV_SEQ_RESV))
			drv_info->seq = 0;

		ret = rpmsg_trysend(rpdev->ept, drv_disable,
					sizeof(*drv_disable));
		if (!ret) {
			ret = wait_for_completion_timeout(&drv_info->completion,
					msecs_to_jiffies(drv_info->timeout_ms));
			if (!ret)
				PCIE_ERR(pcie_dev,
					"PCIe: RC%d: DRV: completion timeout for rpmsg\n",
					pcie_dev->rc_idx);
		} else {
			PCIE_ERR(pcie_dev,
				"PCIe: RC%d: DRV: failed to send rpmsg\n",
				pcie_dev->rc_idx);
		}
	}
	if (rpdev)
		msm_pcie_drv_send_rpmsg(pcie_dev, rpdev,
					&drv_info->drv_disable);

	/* scale CX and rate change based on current GEN speed */
	current_link_speed = readl_relaxed(pcie_dev->dm_core +
@@ -6921,8 +6951,6 @@ static int msm_pcie_drv_suspend(struct msm_pcie_dev_t *pcie_dev,
{
	struct rpmsg_device *rpdev = pcie_drv.rpdev;
	struct msm_pcie_drv_info *drv_info = pcie_dev->drv_info;
	struct msm_pcie_drv_msg *drv_enable = &drv_info->drv_enable;
	struct msm_pcie_drv_tre *pkt = &drv_enable->pkt;
	struct msm_pcie_clk_info_t *clk_info;
	int ret, i;

@@ -6940,36 +6968,12 @@ static int msm_pcie_drv_suspend(struct msm_pcie_dev_t *pcie_dev,
	}

	mutex_lock(&pcie_dev->recovery_lock);
	reinit_completion(&drv_info->completion);

	/* disable global irq - no more linkdown/aer detection */
	disable_irq(pcie_dev->irq[MSM_PCIE_INT_GLOBAL_INT].num);

	if (options & MSM_PCIE_CONFIG_NO_L1SS_TO)
		pkt->dword[2] = 0;
	else
		pkt->dword[2] = drv_info->l1ss_timeout_us / 1000;

	drv_info->reply_seq = drv_info->seq++;
	drv_enable->hdr.seq = drv_info->reply_seq;

	if (unlikely(drv_info->seq == MSM_PCIE_DRV_SEQ_RESV))
		drv_info->seq = 0;

	ret = rpmsg_trysend(rpdev->ept, drv_enable, sizeof(*drv_enable));
	ret = msm_pcie_drv_send_rpmsg(pcie_dev, rpdev, &drv_info->drv_enable);
	if (ret) {
		PCIE_ERR(pcie_dev, "PCIe: RC%d: DRV: failed to send rpmsg\n",
			pcie_dev->rc_idx);
		ret = -EBUSY;
		goto out;
	}

	ret = wait_for_completion_timeout(&drv_info->completion,
					msecs_to_jiffies(drv_info->timeout_ms));
	if (!ret) {
		PCIE_ERR(pcie_dev,
			"PCIe: RC%d: DRV: completion timeout for rpmsg\n",
			pcie_dev->rc_idx);
		ret = -EBUSY;
		goto out;
	}
@@ -7007,6 +7011,11 @@ static int msm_pcie_drv_suspend(struct msm_pcie_dev_t *pcie_dev,

	msm_pcie_vreg_deinit(pcie_dev);

	/* enable L1ss sleep if client allows it */
	if (!(options & MSM_PCIE_CONFIG_NO_L1SS_TO))
		msm_pcie_drv_send_rpmsg(pcie_dev, rpdev,
					&drv_info->drv_enable_l1ss_sleep);

	mutex_unlock(&pcie_dev->setup_lock);
	mutex_unlock(&pcie_dev->recovery_lock);