Commit ab87603b authored by Kai-Heng Feng's avatar Kai-Heng Feng Committed by David S. Miller
Browse files

net: wwan: t7xx: Ensure init is completed before system sleep



When the system attempts to sleep while mtk_t7xx is not ready, the driver
cannot put the device to sleep:
[   12.472918] mtk_t7xx 0000:57:00.0: [PM] Exiting suspend, modem in invalid state
[   12.472936] mtk_t7xx 0000:57:00.0: PM: pci_pm_suspend(): t7xx_pci_pm_suspend+0x0/0x20 [mtk_t7xx] returns -14
[   12.473678] mtk_t7xx 0000:57:00.0: PM: dpm_run_callback(): pci_pm_suspend+0x0/0x1b0 returns -14
[   12.473711] mtk_t7xx 0000:57:00.0: PM: failed to suspend async: error -14
[   12.764776] PM: Some devices failed to suspend, or early wake event detected

Mediatek confirmed the device can take a rather long time to complete
its initialization, so wait for up to 20 seconds until init is done.

Signed-off-by: default avatarKai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9ba9485b
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#define T7XX_PCI_IREG_BASE		0
#define T7XX_PCI_EREG_BASE		2

#define T7XX_INIT_TIMEOUT		20
#define PM_SLEEP_DIS_TIMEOUT_MS		20
#define PM_ACK_TIMEOUT_MS		1500
#define PM_AUTOSUSPEND_MS		20000
@@ -96,6 +97,7 @@ static int t7xx_pci_pm_init(struct t7xx_pci_dev *t7xx_dev)
	spin_lock_init(&t7xx_dev->md_pm_lock);
	init_completion(&t7xx_dev->sleep_lock_acquire);
	init_completion(&t7xx_dev->pm_sr_ack);
	init_completion(&t7xx_dev->init_done);
	atomic_set(&t7xx_dev->md_pm_state, MTK_PM_INIT);

	device_init_wakeup(&pdev->dev, true);
@@ -124,6 +126,7 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev)
	pm_runtime_mark_last_busy(&t7xx_dev->pdev->dev);
	pm_runtime_allow(&t7xx_dev->pdev->dev);
	pm_runtime_put_noidle(&t7xx_dev->pdev->dev);
	complete_all(&t7xx_dev->init_done);
}

static int t7xx_pci_pm_reinit(struct t7xx_pci_dev *t7xx_dev)
@@ -529,6 +532,20 @@ static void t7xx_pci_shutdown(struct pci_dev *pdev)
	__t7xx_pci_pm_suspend(pdev);
}

static int t7xx_pci_pm_prepare(struct device *dev)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	struct t7xx_pci_dev *t7xx_dev;

	t7xx_dev = pci_get_drvdata(pdev);
	if (!wait_for_completion_timeout(&t7xx_dev->init_done, T7XX_INIT_TIMEOUT * HZ)) {
		dev_warn(dev, "Not ready for system sleep.\n");
		return -ETIMEDOUT;
	}

	return 0;
}

static int t7xx_pci_pm_suspend(struct device *dev)
{
	return __t7xx_pci_pm_suspend(to_pci_dev(dev));
@@ -555,6 +572,7 @@ static int t7xx_pci_pm_runtime_resume(struct device *dev)
}

static const struct dev_pm_ops t7xx_pci_pm_ops = {
	.prepare = t7xx_pci_pm_prepare,
	.suspend = t7xx_pci_pm_suspend,
	.resume = t7xx_pci_pm_resume,
	.resume_noirq = t7xx_pci_pm_resume_noirq,
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ struct t7xx_pci_dev {
	struct t7xx_modem	*md;
	struct t7xx_ccmni_ctrl	*ccmni_ctlb;
	bool			rgu_pci_irq_en;
	struct completion	init_done;

	/* Low Power Items */
	struct list_head	md_pm_entities;