Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Kai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Kai-Heng Feng and committed by
David S. Miller
ab87603b 9ba9485b

+19
+18
drivers/net/wwan/t7xx/t7xx_pci.c
··· 45 45 #define T7XX_PCI_IREG_BASE 0 46 46 #define T7XX_PCI_EREG_BASE 2 47 47 48 + #define T7XX_INIT_TIMEOUT 20 48 49 #define PM_SLEEP_DIS_TIMEOUT_MS 20 49 50 #define PM_ACK_TIMEOUT_MS 1500 50 51 #define PM_AUTOSUSPEND_MS 20000 ··· 97 96 spin_lock_init(&t7xx_dev->md_pm_lock); 98 97 init_completion(&t7xx_dev->sleep_lock_acquire); 99 98 init_completion(&t7xx_dev->pm_sr_ack); 99 + init_completion(&t7xx_dev->init_done); 100 100 atomic_set(&t7xx_dev->md_pm_state, MTK_PM_INIT); 101 101 102 102 device_init_wakeup(&pdev->dev, true); ··· 126 124 pm_runtime_mark_last_busy(&t7xx_dev->pdev->dev); 127 125 pm_runtime_allow(&t7xx_dev->pdev->dev); 128 126 pm_runtime_put_noidle(&t7xx_dev->pdev->dev); 127 + complete_all(&t7xx_dev->init_done); 129 128 } 130 129 131 130 static int t7xx_pci_pm_reinit(struct t7xx_pci_dev *t7xx_dev) ··· 532 529 __t7xx_pci_pm_suspend(pdev); 533 530 } 534 531 532 + static int t7xx_pci_pm_prepare(struct device *dev) 533 + { 534 + struct pci_dev *pdev = to_pci_dev(dev); 535 + struct t7xx_pci_dev *t7xx_dev; 536 + 537 + t7xx_dev = pci_get_drvdata(pdev); 538 + if (!wait_for_completion_timeout(&t7xx_dev->init_done, T7XX_INIT_TIMEOUT * HZ)) { 539 + dev_warn(dev, "Not ready for system sleep.\n"); 540 + return -ETIMEDOUT; 541 + } 542 + 543 + return 0; 544 + } 545 + 535 546 static int t7xx_pci_pm_suspend(struct device *dev) 536 547 { 537 548 return __t7xx_pci_pm_suspend(to_pci_dev(dev)); ··· 572 555 } 573 556 574 557 static const struct dev_pm_ops t7xx_pci_pm_ops = { 558 + .prepare = t7xx_pci_pm_prepare, 575 559 .suspend = t7xx_pci_pm_suspend, 576 560 .resume = t7xx_pci_pm_resume, 577 561 .resume_noirq = t7xx_pci_pm_resume_noirq,
+1
drivers/net/wwan/t7xx/t7xx_pci.h
··· 69 69 struct t7xx_modem *md; 70 70 struct t7xx_ccmni_ctrl *ccmni_ctlb; 71 71 bool rgu_pci_irq_en; 72 + struct completion init_done; 72 73 73 74 /* Low Power Items */ 74 75 struct list_head md_pm_entities;