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

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

Merge "msm: ep_pcie: Prevent apps suspend in active state"

parents 1b0e3f90 e599aa24
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -406,7 +406,6 @@ struct ep_pcie_dev_t {
	bool                         config_mmio_init;
	bool                         enumerated;
	enum ep_pcie_link_status     link_status;
	bool                         perst_deast;
	bool                         power_on;
	bool                         suspending;
	bool                         l23_ready;
@@ -414,6 +413,8 @@ struct ep_pcie_dev_t {
	struct ep_pcie_msi_config    msi_cfg;
	bool                         no_notify;
	bool                         client_ready;
	atomic_t		     ep_pcie_dev_wake;
	atomic_t                     perst_deast;

	struct ep_pcie_register_event *event_reg;
	struct work_struct	     handle_perst_work;
+64 −8
Original line number Diff line number Diff line
@@ -1805,7 +1805,7 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
		ret = EP_PCIE_ERROR;
		goto link_fail;
	} else {
		dev->perst_deast = true;
		atomic_set(&dev->perst_deast, 1);
		if (opt & EP_PCIE_OPT_AST_WAKE) {
			/* deassert PCIe WAKE# */
			EP_PCIE_DBG(dev,
@@ -1971,11 +1971,19 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
int ep_pcie_core_disable_endpoint(void)
{
	int rc = 0;
	u32 val = 0;
	unsigned long irqsave_flags;
	struct ep_pcie_dev_t *dev = &ep_pcie_dev;

	EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);

	mutex_lock(&dev->setup_mtx);
	if (atomic_read(&dev->perst_deast)) {
		EP_PCIE_DBG(dev,
			"PCIe V%d: PERST is de-asserted, exiting disable\n",
			dev->rev);
		goto out;
	}

	if (!dev->power_on) {
		EP_PCIE_DBG(dev,
@@ -1992,9 +2000,25 @@ int ep_pcie_core_disable_endpoint(void)
			dev->rev);
	}

	val =  readl_relaxed(dev->elbi + PCIE20_ELBI_SYS_STTS);
	EP_PCIE_DBG(dev, "PCIe V%d: LTSSM_STATE during disable:0x%x\n",
		dev->rev, (val >> 0xC) & 0x3f);
	ep_pcie_pipe_clk_deinit(dev);
	ep_pcie_clk_deinit(dev);
	ep_pcie_vreg_deinit(dev);

	spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
	if (atomic_read(&dev->ep_pcie_dev_wake) &&
		!atomic_read(&dev->perst_deast)) {
		EP_PCIE_DBG(dev, "PCIe V%d: Released wakelock\n", dev->rev);
		atomic_set(&dev->ep_pcie_dev_wake, 0);
		pm_relax(&dev->pdev->dev);
	} else {
		EP_PCIE_DBG(dev, "PCIe V%d: Bail, Perst-assert:%d wake:%d\n",
			dev->rev, atomic_read(&dev->perst_deast),
				atomic_read(&dev->ep_pcie_dev_wake));
	}
	spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
out:
	mutex_unlock(&dev->setup_mtx);
	return rc;
@@ -2251,12 +2275,25 @@ static void handle_d3cold_func(struct work_struct *work)
{
	struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t,
					handle_d3cold_work);
	unsigned long irqsave_flags;

	EP_PCIE_DBG(dev,
		"PCIe V%d: shutdown PCIe link due to PERST assertion before BME is set\n",
		dev->rev);
	ep_pcie_core_disable_endpoint();
	dev->no_notify = false;
	spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
	if (atomic_read(&dev->ep_pcie_dev_wake) &&
		!atomic_read(&dev->perst_deast)) {
		atomic_set(&dev->ep_pcie_dev_wake, 0);
		pm_relax(&dev->pdev->dev);
		EP_PCIE_DBG(dev, "PCIe V%d: Released wakelock\n", dev->rev);
	} else {
		EP_PCIE_DBG(dev, "PCIe V%d: Bail, Perst-assert:%d wake:%d\n",
			dev->rev, atomic_read(&dev->perst_deast),
				atomic_read(&dev->ep_pcie_dev_wake));
	}
	spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
}

static void handle_bme_func(struct work_struct *work)
@@ -2294,14 +2331,24 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data)
	}

	if (perst) {
		dev->perst_deast = true;
		atomic_set(&dev->perst_deast, 1);
		dev->perst_deast_counter++;
		/*
		 * Hold a wakelock to avoid missing BME and other
		 * interrupts if apps goes into suspend before BME is set.
		 */
		if (!atomic_read(&dev->ep_pcie_dev_wake)) {
			pm_stay_awake(&dev->pdev->dev);
			atomic_set(&dev->ep_pcie_dev_wake, 1);
			EP_PCIE_DBG(dev, "PCIe V%d: Acquired wakelock\n",
				dev->rev);
		}
		EP_PCIE_DBG(dev,
			"PCIe V%d: No. %ld PERST deassertion\n",
			dev->rev, dev->perst_deast_counter);
		ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST);
	} else {
		dev->perst_deast = false;
		atomic_set(&dev->perst_deast, 0);
		dev->perst_ast_counter++;
		EP_PCIE_DBG(dev,
			"PCIe V%d: No. %ld PERST assertion\n",
@@ -2552,13 +2599,14 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev)
	 * based on the next expected level of the gpio
	 */
	if (gpio_get_value(dev->gpio[EP_PCIE_GPIO_PERST].num) == 1)
		dev->perst_deast = true;
		atomic_set(&dev->perst_deast, 1);

	/* register handler for PERST interrupt */
	perst_irq = gpio_to_irq(dev->gpio[EP_PCIE_GPIO_PERST].num);
	ret = devm_request_irq(pdev, perst_irq,
		ep_pcie_handle_perst_irq,
		((dev->perst_deast ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH)
		((atomic_read(&dev->perst_deast) ?
			IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH)
			| IRQF_EARLY_RESUME),
		"ep_pcie_perst", dev);
	if (ret) {
@@ -2953,7 +3001,7 @@ static int ep_pcie_core_wakeup_host(enum ep_pcie_event event)
	if (event == EP_PCIE_EVENT_PM_D3_HOT)
		ep_pcie_core_issue_inband_pme();

	if (dev->perst_deast && !dev->l23_ready) {
	if (atomic_read(&dev->perst_deast) && !dev->l23_ready) {
		EP_PCIE_ERR(dev,
			"PCIe V%d: request to assert WAKE# when PERST is de-asserted and D3hot is not received\n",
			dev->rev);
@@ -2964,7 +3012,7 @@ static int ep_pcie_core_wakeup_host(enum ep_pcie_event event)
	EP_PCIE_DBG(dev,
		"PCIe V%d: No. %ld to assert PCIe WAKE#; perst is %s de-asserted; D3hot is %s received\n",
		dev->rev, dev->wake_counter,
		dev->perst_deast ? "" : "not",
		atomic_read(&dev->perst_deast) ? "" : "not",
		dev->l23_ready ? "" : "not");
	/*
	 * Assert WAKE# GPIO until link is back to L0.
@@ -3219,6 +3267,14 @@ static int ep_pcie_probe(struct platform_device *pdev)
		goto irq_failure;
	}

	/*
	 * Wakelock is needed to avoid missing BME and other
	 * interrupts if apps goes into suspend before host
	 * sets them.
	 */
	device_init_wakeup(&ep_pcie_dev.pdev->dev, true);
	atomic_set(&ep_pcie_dev.ep_pcie_dev_wake, 0);

	if (ep_pcie_dev.perst_enum &&
		!gpio_get_value(ep_pcie_dev.gpio[EP_PCIE_GPIO_PERST].num)) {
		EP_PCIE_DBG2(&ep_pcie_dev,