From 31abb40d398117cc6e0f220f104526ed7e5efd10 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Fri, 17 Apr 2020 15:37:01 -0700 Subject: [PATCH] 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: Tony Truong --- drivers/pci/controller/pci-msm.c | 163 ++++++++++++++++--------------- 1 file changed, 86 insertions(+), 77 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 5cf831e71439..d4537de21c46 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -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);