All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
@ 2022-01-20 14:50 Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
                   ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-20 14:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
weird tricks to keep it from runtime suspending.

So use those helpers at right places to properly manage runtime PM.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 drivers/mmc/host/rtsx_pci_sdmmc.c | 44 +++++++++++++++++++++++--------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 58cfaffa3c2d8..2656dc840a3a5 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -806,6 +806,7 @@ static void sd_request(struct work_struct *work)
 	struct mmc_request *mrq = host->mrq;
 	struct mmc_command *cmd = mrq->cmd;
 	struct mmc_data *data = mrq->data;
+	struct device *dev = &host->pdev->dev;
 
 	unsigned int data_size = 0;
 	int err;
@@ -822,6 +823,7 @@ static void sd_request(struct work_struct *work)
 	}
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -858,6 +860,8 @@ static void sd_request(struct work_struct *work)
 			data->bytes_xfered = data->blocks * data->blksz;
 	}
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 finish:
@@ -1080,6 +1084,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 
 	if (host->eject)
 		return;
@@ -1088,6 +1093,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		return;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1121,6 +1127,8 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth,
 			host->initial_mode, host->double_clk, host->vpclk);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 }
 
@@ -1128,6 +1136,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int ro = 0;
 	u32 val;
 
@@ -1135,6 +1144,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 		return -ENOMEDIUM;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1144,6 +1154,8 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 	if (val & SD_WRITE_PROTECT)
 		ro = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return ro;
@@ -1153,6 +1165,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int cd = 0;
 	u32 val;
 
@@ -1160,6 +1173,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 		return cd;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1169,6 +1183,8 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 	if (val & SD_EXIST)
 		cd = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return cd;
@@ -1251,6 +1267,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 	u8 voltage;
 
@@ -1265,6 +1282,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1294,6 +1312,8 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 	err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
 			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1303,6 +1323,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 
 	if (host->eject)
@@ -1313,6 +1334,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1345,6 +1367,8 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true);
 
 out:
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1495,12 +1519,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
 
 	realtek_init_host(host);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
-		pm_runtime_use_autosuspend(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
-	}
-
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_use_autosuspend(&pdev->dev);
 
 	mmc_add_host(mmc);
 
@@ -1521,11 +1545,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
 	mmc = host->mmc;
 
-	if (pcr->rtd3_en) {
-		pm_runtime_dont_use_autosuspend(&pdev->dev);
-		pm_runtime_disable(&pdev->dev);
-	}
-
 	cancel_work_sync(&host->work);
 
 	mutex_lock(&host->host_mutex);
@@ -1548,6 +1567,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 
 	flush_work(&host->work);
 
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	mmc_free_host(mmc);
 
 	dev_dbg(&(pdev->dev),
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-20 14:50 [PATCH 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
@ 2022-01-20 14:50 ` Kai-Heng Feng
  2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
  2 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-20 14:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Yang Li, Christophe JAILLET,
	linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
uses "rtd3_work" and "idle_work" to manage it's own runtime PM state
machine.

When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
correctly, all the additional works can be managed by generic runtime PM
helpers.

So consolidate "idle_work" and "rtd3_work" into generic runtime idle
callback and runtime suspend callback, respectively.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 drivers/misc/cardreader/rtsx_pcr.c | 123 +++++++++++------------------
 include/linux/rtsx_pci.h           |   1 -
 2 files changed, 44 insertions(+), 80 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 6ac509c1821c9..1dcf98b597569 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
 	if (pcr->remove_pci)
 		return;
 
-	if (pcr->rtd3_en)
-		if (pcr->is_runtime_suspended) {
-			pm_runtime_get(&(pcr->pci->dev));
-			pcr->is_runtime_suspended = false;
-		}
-
 	if (pcr->state != PDEV_STAT_RUN) {
 		pcr->state = PDEV_STAT_RUN;
 		if (pcr->ops->enable_auto_blink)
 			pcr->ops->enable_auto_blink(pcr);
 		rtsx_pm_full_on(pcr);
 	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-	if (!pcr->is_runtime_suspended)
-		pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if (pcr->rtd3_en)
-		mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
 static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 {
 	/* Set relink_time to 0 */
@@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 	pcr->card_inserted = 0;
 	pcr->card_removed = 0;
 	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
 	pcr->msi_en = msi_en;
 	if (pcr->msi_en) {
@@ -1623,20 +1580,16 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
 	}
 
-	if (pcr->rtd3_en) {
-		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-		pm_runtime_allow(&pcidev->dev);
-		pm_runtime_enable(&pcidev->dev);
-		pcr->is_runtime_suspended = false;
-	}
-
 
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
 		goto free_slots;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+	if (pcr->rtd3_en) {
+		pm_runtime_allow(&pcidev->dev);
+		pm_runtime_put(&pcidev->dev);
+	}
 
 	return 0;
 
@@ -1668,10 +1621,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	struct pcr_handle *handle = pci_get_drvdata(pcidev);
 	struct rtsx_pcr *pcr = handle->pcr;
 
-	if (pcr->rtd3_en)
-		pm_runtime_get_noresume(&pcr->pci->dev);
-
 	pcr->remove_pci = true;
+	if (pcr->rtd3_en) {
+		pm_runtime_get_sync(&pcidev->dev);
+		pm_runtime_forbid(&pcidev->dev);
+	}
 
 	/* Disable interrupts at the pcr level */
 	spin_lock_irq(&pcr->lock);
@@ -1680,9 +1634,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	spin_unlock_irq(&pcr->lock);
 
 	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-	if (pcr->rtd3_en)
-		cancel_delayed_work_sync(&pcr->rtd3_work);
 
 	mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1651,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	idr_remove(&rtsx_pci_idr, pcr->id);
 	spin_unlock(&rtsx_pci_lock);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_disable(&pcr->pci->dev);
-		pm_runtime_put_noidle(&pcr->pci->dev);
-	}
-
 	kfree(pcr->slots);
 	kfree(pcr);
 	kfree(handle);
@@ -1726,7 +1672,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	pcr = handle->pcr;
 
 	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1760,8 +1705,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 	if (ret)
 		goto out;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
 	mutex_unlock(&pcr->pcr_mutex);
 	return ret;
@@ -1786,6 +1729,32 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 		pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+	struct pci_dev *pcidev = to_pci_dev(device);
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	pm_schedule_suspend(device, 5000);
+
+	return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
@@ -1794,31 +1763,29 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->rtd3_work);
-	cancel_delayed_work(&pcr->idle_work);
+	if (!pcr->rtd3_en)
+		return -EBUSY;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
-	pcr->is_runtime_suspended = true;
-
 	return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+	dev_dbg(device, "--> %s\n", __func__);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1834,8 +1801,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 				pcr->slots[RTSX_SD_CARD].p_dev);
 	}
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1850,7 +1815,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 4ab7bfc675f11..671aaca8529c6 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1212,7 +1212,6 @@ struct rtsx_pcr {
 	unsigned int			cur_clock;
 	bool				remove_pci;
 	bool				msi_en;
-	bool				is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50		(1 << 0)
 #define EXTRA_CAPS_SD_SDR104		(1 << 1)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 3/4] misc: rtsx: Cleanup power management ops
  2022-01-20 14:50 [PATCH 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
@ 2022-01-20 14:50 ` Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-20 14:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

- Use cancel_delayed_work_sync to ensure there's no race with
  carddet_work.

- Remove device_wakeup_disable to save some CPU cycles. If the device
  really has ACPI _DSW then the wakeup should be disabled in probe
  routine.

- Remove fetch_vendor_settings from runtime resume routine, since they
  are already saved in "struct rtsx_pcr".

Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 drivers/misc/cardreader/rtsx_pcr.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 1dcf98b597569..8107c85028c37 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1671,14 +1671,12 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
 
-	cancel_delayed_work(&pcr->carddet_work);
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
-	device_wakeup_disable(dev_d);
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1791,9 +1789,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
 
-	if (pcr->ops->fetch_vendor_settings)
-		pcr->ops->fetch_vendor_settings(pcr);
-
 	rtsx_pci_init_hw(pcr);
 
 	if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) {
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 4/4] misc: rtsx: Quiesce rts5249 on system suspend
  2022-01-20 14:50 [PATCH 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
  2022-01-20 14:50 ` [PATCH 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
@ 2022-01-20 14:50 ` Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-20 14:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Set more registers in force_power_down callback to avoid S3 wakeup from
hotplugging cards.

This is originally written by Ricky WU.

Link: https://lore.kernel.org/lkml/c4525b4738f94483b9b8f8571fc80646@realtek.com/
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 drivers/misc/cardreader/rtl8411.c  |  2 +-
 drivers/misc/cardreader/rts5209.c  |  2 +-
 drivers/misc/cardreader/rts5228.c  |  2 +-
 drivers/misc/cardreader/rts5229.c  |  2 +-
 drivers/misc/cardreader/rts5249.c  | 31 ++++++++++++++++++++++++++++--
 drivers/misc/cardreader/rts5261.c  |  2 +-
 drivers/misc/cardreader/rtsx_pcr.c | 14 +++++++-------
 drivers/misc/cardreader/rtsx_pcr.h |  1 +
 include/linux/rtsx_pci.h           |  2 +-
 9 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/cardreader/rtl8411.c b/drivers/misc/cardreader/rtl8411.c
index 4c5621b17a6fb..06457e875a90c 100644
--- a/drivers/misc/cardreader/rtl8411.c
+++ b/drivers/misc/cardreader/rtl8411.c
@@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c
index 29f5414072bf1..52b0a476ba51f 100644
--- a/drivers/misc/cardreader/rts5209.c
+++ b/drivers/misc/cardreader/rts5209.c
@@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	}
 }
 
-static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c
index ffc128278613b..ffe3afbf8bfed 100644
--- a/drivers/misc/cardreader/rts5228.c
+++ b/drivers/misc/cardreader/rts5228.c
@@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
 	return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
 }
 
-static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rts5229.c b/drivers/misc/cardreader/rts5229.c
index c748eaf1ec1f9..b0edd8006d52f 100644
--- a/drivers/misc/cardreader/rts5229.c
+++ b/drivers/misc/cardreader/rts5229.c
@@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
 }
diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c
index 53f3a1f45c4a7..91d240dd68faa 100644
--- a/drivers/misc/cardreader/rts5249.c
+++ b/drivers/misc/cardreader/rts5249.c
@@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
 	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
 
-	pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+		pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
 
 	if (rtsx_check_mmc_support(reg))
 		pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
@@ -143,6 +144,27 @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
 	return 0;
 }
 
+static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+	/* Set relink_time to 0 */
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+				RELINK_TIME_MASK, 0);
+
+	rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+	if (!runtime) {
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+				CD_RESUME_EN_MASK, 0);
+		rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00);
+		rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20);
+	}
+
+	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
 static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr)
 {
 	u8 cnt, sv;
@@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 
 	rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
 
-	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
 		rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN);
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+			CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+	}
 
 	if (pcr->rtd3_en) {
 		if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
@@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
 	.card_power_on = rtsx_base_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rtsx_base_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
@@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
 	.card_power_on = rts525a_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rts525a_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 1fd4e0e507302..64333347c14a4 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg);
 }
 
-static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 8107c85028c37..576c72e1580a6 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1086,7 +1086,7 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtsx_base_force_power_down(struct rtsx_pcr *pcr)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -1100,7 +1100,7 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
 }
 
-static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	if (pcr->ops->turn_off_led)
 		pcr->ops->turn_off_led(pcr);
@@ -1112,9 +1112,9 @@ static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
 
 	if (pcr->ops->force_power_down)
-		pcr->ops->force_power_down(pcr, pm_state);
+		pcr->ops->force_power_down(pcr, pm_state, runtime);
 	else
-		rtsx_base_force_power_down(pcr, pm_state);
+		rtsx_base_force_power_down(pcr);
 }
 
 void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
@@ -1675,7 +1675,7 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 
 	mutex_lock(&pcr->pcr_mutex);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, false);
 
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
@@ -1719,7 +1719,7 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S1, false);
 
 	pci_disable_device(pcidev);
 	free_irq(pcr->irq, (void *)pcr);
@@ -1770,7 +1770,7 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, true);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
index daf057c4eea62..aa0ebd6672277 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -25,6 +25,7 @@
 #define REG_EFUSE_POWEROFF		0x00
 #define RTS5250_CLK_CFG3		0xFF79
 #define RTS525A_CFG_MEM_PD		0xF0
+#define RTS524A_AUTOLOAD_CFG1		0xFF7C
 #define RTS524A_PM_CTRL3		0xFF7E
 #define RTS525A_BIOS_CFG		0xFF2D
 #define RTS525A_LOAD_BIOS_FLAG	0x01
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 671aaca8529c6..7e2f2da756cde 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1095,7 +1095,7 @@ struct pcr_ops {
 	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
 	int		(*conv_clk_and_div_n)(int clk, int dir);
 	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
-	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
+	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime);
 	void		(*stop_cmd)(struct rtsx_pcr *pcr);
 
 	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-20 14:50 ` [PATCH 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
@ 2022-01-21  1:40   ` Kai-Heng Feng
  2022-01-21  3:57     ` Ricky WU
                       ` (4 more replies)
  0 siblings, 5 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-21  1:40 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
uses "rtd3_work" and "idle_work" to manage it's own runtime PM state
machine.

When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
correctly, all the additional works can be managed by generic runtime PM
helpers.

So consolidate "idle_work" and "rtd3_work" into generic runtime idle
callback and runtime suspend callback, respectively.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v2:
 - Remove unused idle_work and rtd3_work from rtsx_pcr.

 drivers/misc/cardreader/rtsx_pcr.c | 123 +++++++++++------------------
 include/linux/rtsx_pci.h           |   3 -
 2 files changed, 44 insertions(+), 82 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 6ac509c1821c9..1dcf98b597569 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
 	if (pcr->remove_pci)
 		return;
 
-	if (pcr->rtd3_en)
-		if (pcr->is_runtime_suspended) {
-			pm_runtime_get(&(pcr->pci->dev));
-			pcr->is_runtime_suspended = false;
-		}
-
 	if (pcr->state != PDEV_STAT_RUN) {
 		pcr->state = PDEV_STAT_RUN;
 		if (pcr->ops->enable_auto_blink)
 			pcr->ops->enable_auto_blink(pcr);
 		rtsx_pm_full_on(pcr);
 	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-	if (!pcr->is_runtime_suspended)
-		pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if (pcr->rtd3_en)
-		mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
 static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 {
 	/* Set relink_time to 0 */
@@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 	pcr->card_inserted = 0;
 	pcr->card_removed = 0;
 	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
 	pcr->msi_en = msi_en;
 	if (pcr->msi_en) {
@@ -1623,20 +1580,16 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
 	}
 
-	if (pcr->rtd3_en) {
-		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-		pm_runtime_allow(&pcidev->dev);
-		pm_runtime_enable(&pcidev->dev);
-		pcr->is_runtime_suspended = false;
-	}
-
 
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
 		goto free_slots;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+	if (pcr->rtd3_en) {
+		pm_runtime_allow(&pcidev->dev);
+		pm_runtime_put(&pcidev->dev);
+	}
 
 	return 0;
 
@@ -1668,10 +1621,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	struct pcr_handle *handle = pci_get_drvdata(pcidev);
 	struct rtsx_pcr *pcr = handle->pcr;
 
-	if (pcr->rtd3_en)
-		pm_runtime_get_noresume(&pcr->pci->dev);
-
 	pcr->remove_pci = true;
+	if (pcr->rtd3_en) {
+		pm_runtime_get_sync(&pcidev->dev);
+		pm_runtime_forbid(&pcidev->dev);
+	}
 
 	/* Disable interrupts at the pcr level */
 	spin_lock_irq(&pcr->lock);
@@ -1680,9 +1634,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	spin_unlock_irq(&pcr->lock);
 
 	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-	if (pcr->rtd3_en)
-		cancel_delayed_work_sync(&pcr->rtd3_work);
 
 	mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1651,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	idr_remove(&rtsx_pci_idr, pcr->id);
 	spin_unlock(&rtsx_pci_lock);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_disable(&pcr->pci->dev);
-		pm_runtime_put_noidle(&pcr->pci->dev);
-	}
-
 	kfree(pcr->slots);
 	kfree(pcr);
 	kfree(handle);
@@ -1726,7 +1672,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	pcr = handle->pcr;
 
 	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1760,8 +1705,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 	if (ret)
 		goto out;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
 	mutex_unlock(&pcr->pcr_mutex);
 	return ret;
@@ -1786,6 +1729,32 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 		pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+	struct pci_dev *pcidev = to_pci_dev(device);
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	pm_schedule_suspend(device, 5000);
+
+	return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
@@ -1794,31 +1763,29 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->rtd3_work);
-	cancel_delayed_work(&pcr->idle_work);
+	if (!pcr->rtd3_en)
+		return -EBUSY;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
-	pcr->is_runtime_suspended = true;
-
 	return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+	dev_dbg(device, "--> %s\n", __func__);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1834,8 +1801,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 				pcr->slots[RTSX_SD_CARD].p_dev);
 	}
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1850,7 +1815,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 4ab7bfc675f11..89b7d34e25b63 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1201,8 +1201,6 @@ struct rtsx_pcr {
 	unsigned int			card_exist;
 
 	struct delayed_work		carddet_work;
-	struct delayed_work		idle_work;
-	struct delayed_work		rtd3_work;
 
 	spinlock_t			lock;
 	struct mutex			pcr_mutex;
@@ -1212,7 +1210,6 @@ struct rtsx_pcr {
 	unsigned int			cur_clock;
 	bool				remove_pci;
 	bool				msi_en;
-	bool				is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50		(1 << 0)
 #define EXTRA_CAPS_SD_SDR104		(1 << 1)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* RE: [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
@ 2022-01-21  3:57     ` Ricky WU
  2022-01-21  4:08       ` Kai-Heng Feng
  2022-01-21  6:31     ` [PATCH v3 " Kai-Heng Feng
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: Ricky WU @ 2022-01-21  3:57 UTC (permalink / raw)
  To: Kai-Heng Feng, arnd, gregkh, ulf.hansson
  Cc: linux-pm, Christophe JAILLET, Yang Li, linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Friday, January 21, 2022 9:41 AM
> To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> Ricky WU <ricky_wu@realtek.com>; Christophe JAILLET
> <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> linux-kernel@vger.kernel.org
> Subject: [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
> 
> Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> "rtd3_work" and "idle_work" to manage it's own runtime PM state machine.
> 
> When its child device, rtsx_pci_sdmmc, uses runtime PM refcount correctly, all
> the additional works can be managed by generic runtime PM helpers.
> 
> So consolidate "idle_work" and "rtd3_work" into generic runtime idle callback
> and runtime suspend callback, respectively.
> 

This idle_work is not runtime_idle, this is for aspm setting
Not only for support RPM, so this idle_work can not be remove....

Our original Idle_work is a power saveing function, It is a delay_work for 200 msec  ,
If no work comes in 200 msec than go to idle_work to set power saveing setting.....  

> Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> Cc: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v2:
>  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> 
>  drivers/misc/cardreader/rtsx_pcr.c | 123 +++++++++++------------------
>  include/linux/rtsx_pci.h           |   3 -
>  2 files changed, 44 insertions(+), 82 deletions(-)
> 
> diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> b/drivers/misc/cardreader/rtsx_pcr.c
> index 6ac509c1821c9..1dcf98b597569 100644
> --- a/drivers/misc/cardreader/rtsx_pcr.c
> +++ b/drivers/misc/cardreader/rtsx_pcr.c
> @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
>  	if (pcr->remove_pci)
>  		return;
> 
> -	if (pcr->rtd3_en)
> -		if (pcr->is_runtime_suspended) {
> -			pm_runtime_get(&(pcr->pci->dev));
> -			pcr->is_runtime_suspended = false;
> -		}
> -
>  	if (pcr->state != PDEV_STAT_RUN) {
>  		pcr->state = PDEV_STAT_RUN;
>  		if (pcr->ops->enable_auto_blink)
>  			pcr->ops->enable_auto_blink(pcr);
>  		rtsx_pm_full_on(pcr);
>  	}
> -
> -	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
>  }
>  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> 
> @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr
> *pcr)
>  	rtsx_comm_pm_power_saving(pcr);
>  }
> 
> -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> -	struct delayed_work *dwork = to_delayed_work(work);
> -	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
> -
> -	pcr_dbg(pcr, "--> %s\n", __func__);
> -	if (!pcr->is_runtime_suspended)
> -		pm_runtime_put(&(pcr->pci->dev));
> -}
> -
> -static void rtsx_pci_idle_work(struct work_struct *work) -{
> -	struct delayed_work *dwork = to_delayed_work(work);
> -	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
> -
> -	pcr_dbg(pcr, "--> %s\n", __func__);
> -
> -	mutex_lock(&pcr->pcr_mutex);
> -
> -	pcr->state = PDEV_STAT_IDLE;
> -
> -	if (pcr->ops->disable_auto_blink)
> -		pcr->ops->disable_auto_blink(pcr);
> -	if (pcr->ops->turn_off_led)
> -		pcr->ops->turn_off_led(pcr);
> -
> -	rtsx_pm_power_saving(pcr);
> -
> -	mutex_unlock(&pcr->pcr_mutex);
> -
> -	if (pcr->rtd3_en)
> -		mod_delayed_work(system_wq, &pcr->rtd3_work,
> msecs_to_jiffies(10000));
> -}
> -
>  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> {
>  	/* Set relink_time to 0 */
> @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
>  	pcr->card_inserted = 0;
>  	pcr->card_removed = 0;
>  	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> -	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> 
>  	pcr->msi_en = msi_en;
>  	if (pcr->msi_en) {
> @@ -1623,20 +1580,16 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
>  		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
>  	}
> 
> -	if (pcr->rtd3_en) {
> -		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
> -		pm_runtime_allow(&pcidev->dev);
> -		pm_runtime_enable(&pcidev->dev);
> -		pcr->is_runtime_suspended = false;
> -	}
> -
> 
>  	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
>  			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
>  	if (ret < 0)
>  		goto free_slots;
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> +	if (pcr->rtd3_en) {
> +		pm_runtime_allow(&pcidev->dev);
> +		pm_runtime_put(&pcidev->dev);
> +	}
> 
>  	return 0;
> 
> @@ -1668,10 +1621,11 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
>  	struct pcr_handle *handle = pci_get_drvdata(pcidev);
>  	struct rtsx_pcr *pcr = handle->pcr;
> 
> -	if (pcr->rtd3_en)
> -		pm_runtime_get_noresume(&pcr->pci->dev);
> -
>  	pcr->remove_pci = true;
> +	if (pcr->rtd3_en) {
> +		pm_runtime_get_sync(&pcidev->dev);
> +		pm_runtime_forbid(&pcidev->dev);
> +	}
> 
>  	/* Disable interrupts at the pcr level */
>  	spin_lock_irq(&pcr->lock);
> @@ -1680,9 +1634,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
>  	spin_unlock_irq(&pcr->lock);
> 
>  	cancel_delayed_work_sync(&pcr->carddet_work);
> -	cancel_delayed_work_sync(&pcr->idle_work);
> -	if (pcr->rtd3_en)
> -		cancel_delayed_work_sync(&pcr->rtd3_work);
> 
>  	mfd_remove_devices(&pcidev->dev);
> 
> @@ -1700,11 +1651,6 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
>  	idr_remove(&rtsx_pci_idr, pcr->id);
>  	spin_unlock(&rtsx_pci_lock);
> 
> -	if (pcr->rtd3_en) {
> -		pm_runtime_disable(&pcr->pci->dev);
> -		pm_runtime_put_noidle(&pcr->pci->dev);
> -	}
> -
>  	kfree(pcr->slots);
>  	kfree(pcr);
>  	kfree(handle);
> @@ -1726,7 +1672,6 @@ static int __maybe_unused rtsx_pci_suspend(struct
> device *dev_d)
>  	pcr = handle->pcr;
> 
>  	cancel_delayed_work(&pcr->carddet_work);
> -	cancel_delayed_work(&pcr->idle_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> @@ -1760,8 +1705,6 @@ static int __maybe_unused rtsx_pci_resume(struct
> device *dev_d)
>  	if (ret)
>  		goto out;
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> -
>  out:
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return ret;
> @@ -1786,6 +1729,32 @@ static void rtsx_pci_shutdown(struct pci_dev
> *pcidev)
>  		pci_disable_msi(pcr->pci);
>  }
> 
> +static int rtsx_pci_runtime_idle(struct device *device) {
> +	struct pci_dev *pcidev = to_pci_dev(device);
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> +
> +	dev_dbg(device, "--> %s\n", __func__);
> +
> +	mutex_lock(&pcr->pcr_mutex);
> +
> +	pcr->state = PDEV_STAT_IDLE;
> +
> +	if (pcr->ops->disable_auto_blink)
> +		pcr->ops->disable_auto_blink(pcr);
> +	if (pcr->ops->turn_off_led)
> +		pcr->ops->turn_off_led(pcr);
> +
> +	rtsx_pm_power_saving(pcr);
> +
> +	mutex_unlock(&pcr->pcr_mutex);
> +
> +	pm_schedule_suspend(device, 5000);
> +
> +	return -EBUSY;
> +}
> +
>  static int rtsx_pci_runtime_suspend(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31 +1763,29 @@
> static int rtsx_pci_runtime_suspend(struct device *device)
> 
>  	handle = pci_get_drvdata(pcidev);
>  	pcr = handle->pcr;
> -	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	cancel_delayed_work(&pcr->carddet_work);
> -	cancel_delayed_work(&pcr->rtd3_work);
> -	cancel_delayed_work(&pcr->idle_work);
> +	if (!pcr->rtd3_en)
> +		return -EBUSY;
> +
> +	dev_dbg(device, "--> %s\n", __func__);
> +
> +	cancel_delayed_work_sync(&pcr->carddet_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
>  	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> 
>  	mutex_unlock(&pcr->pcr_mutex);
> 
> -	pcr->is_runtime_suspended = true;
> -
>  	return 0;
>  }
> 
>  static int rtsx_pci_runtime_resume(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device);
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> 
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
> -	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> +	dev_dbg(device, "--> %s\n", __func__);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> @@ -1834,8 +1801,6 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
>  				pcr->slots[RTSX_SD_CARD].p_dev);
>  	}
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> -
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return 0;
>  }
> @@ -1850,7 +1815,7 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
> 
>  static const struct dev_pm_ops rtsx_pci_pm_ops = {
>  	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> -	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> rtsx_pci_runtime_resume, NULL)
> +	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> rtsx_pci_runtime_resume,
> +rtsx_pci_runtime_idle)
>  };
> 
>  static struct pci_driver rtsx_pci_driver = { diff --git a/include/linux/rtsx_pci.h
> b/include/linux/rtsx_pci.h index 4ab7bfc675f11..89b7d34e25b63 100644
> --- a/include/linux/rtsx_pci.h
> +++ b/include/linux/rtsx_pci.h
> @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
>  	unsigned int			card_exist;
> 
>  	struct delayed_work		carddet_work;
> -	struct delayed_work		idle_work;
> -	struct delayed_work		rtd3_work;
> 
>  	spinlock_t			lock;
>  	struct mutex			pcr_mutex;
> @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
>  	unsigned int			cur_clock;
>  	bool				remove_pci;
>  	bool				msi_en;
> -	bool				is_runtime_suspended;
> 
>  #define EXTRA_CAPS_SD_SDR50		(1 << 0)
>  #define EXTRA_CAPS_SD_SDR104		(1 << 1)
> --
> 2.33.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  3:57     ` Ricky WU
@ 2022-01-21  4:08       ` Kai-Heng Feng
  2022-01-21  4:15         ` Ricky WU
  0 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-21  4:08 UTC (permalink / raw)
  To: Ricky WU
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

On Fri, Jan 21, 2022 at 11:57 AM Ricky WU <ricky_wu@realtek.com> wrote:
>
> > -----Original Message-----
> > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > Sent: Friday, January 21, 2022 9:41 AM
> > To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> > Ricky WU <ricky_wu@realtek.com>; Christophe JAILLET
> > <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> > linux-kernel@vger.kernel.org
> > Subject: [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
> >
> > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> > "rtd3_work" and "idle_work" to manage it's own runtime PM state machine.
> >
> > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount correctly, all
> > the additional works can be managed by generic runtime PM helpers.
> >
> > So consolidate "idle_work" and "rtd3_work" into generic runtime idle callback
> > and runtime suspend callback, respectively.
> >
>
> This idle_work is not runtime_idle, this is for aspm setting
> Not only for support RPM, so this idle_work can not be remove....

rtsx_pm_power_saving() is called inside rtsx_pci_runtime_idle(), when
the usage refcount becomes zero, before runtime suspend routine.

>
> Our original Idle_work is a power saveing function, It is a delay_work for 200 msec  ,
> If no work comes in 200 msec than go to idle_work to set power saveing setting.....

Have you tested it locally? rtsx_pci_runtime_idle() really does the same thing.

Kai-Heng

>
> > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > Cc: Ricky WU <ricky_wu@realtek.com>
> > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > ---
> > v2:
> >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> >
> >  drivers/misc/cardreader/rtsx_pcr.c | 123 +++++++++++------------------
> >  include/linux/rtsx_pci.h           |   3 -
> >  2 files changed, 44 insertions(+), 82 deletions(-)
> >
> > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > b/drivers/misc/cardreader/rtsx_pcr.c
> > index 6ac509c1821c9..1dcf98b597569 100644
> > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> >       if (pcr->remove_pci)
> >               return;
> >
> > -     if (pcr->rtd3_en)
> > -             if (pcr->is_runtime_suspended) {
> > -                     pm_runtime_get(&(pcr->pci->dev));
> > -                     pcr->is_runtime_suspended = false;
> > -             }
> > -
> >       if (pcr->state != PDEV_STAT_RUN) {
> >               pcr->state = PDEV_STAT_RUN;
> >               if (pcr->ops->enable_auto_blink)
> >                       pcr->ops->enable_auto_blink(pcr);
> >               rtsx_pm_full_on(pcr);
> >       }
> > -
> > -     mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
> >  }
> >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> >
> > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr
> > *pcr)
> >       rtsx_comm_pm_power_saving(pcr);
> >  }
> >
> > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > -     struct delayed_work *dwork = to_delayed_work(work);
> > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
> > -
> > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > -     if (!pcr->is_runtime_suspended)
> > -             pm_runtime_put(&(pcr->pci->dev));
> > -}
> > -
> > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > -     struct delayed_work *dwork = to_delayed_work(work);
> > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
> > -
> > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > -
> > -     mutex_lock(&pcr->pcr_mutex);
> > -
> > -     pcr->state = PDEV_STAT_IDLE;
> > -
> > -     if (pcr->ops->disable_auto_blink)
> > -             pcr->ops->disable_auto_blink(pcr);
> > -     if (pcr->ops->turn_off_led)
> > -             pcr->ops->turn_off_led(pcr);
> > -
> > -     rtsx_pm_power_saving(pcr);
> > -
> > -     mutex_unlock(&pcr->pcr_mutex);
> > -
> > -     if (pcr->rtd3_en)
> > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > msecs_to_jiffies(10000));
> > -}
> > -
> >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> > {
> >       /* Set relink_time to 0 */
> > @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> >       pcr->card_inserted = 0;
> >       pcr->card_removed = 0;
> >       INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> >
> >       pcr->msi_en = msi_en;
> >       if (pcr->msi_en) {
> > @@ -1623,20 +1580,16 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> >       }
> >
> > -     if (pcr->rtd3_en) {
> > -             INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
> > -             pm_runtime_allow(&pcidev->dev);
> > -             pm_runtime_enable(&pcidev->dev);
> > -             pcr->is_runtime_suspended = false;
> > -     }
> > -
> >
> >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
> >       if (ret < 0)
> >               goto free_slots;
> >
> > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > +     if (pcr->rtd3_en) {
> > +             pm_runtime_allow(&pcidev->dev);
> > +             pm_runtime_put(&pcidev->dev);
> > +     }
> >
> >       return 0;
> >
> > @@ -1668,10 +1621,11 @@ static void rtsx_pci_remove(struct pci_dev
> > *pcidev)
> >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> >       struct rtsx_pcr *pcr = handle->pcr;
> >
> > -     if (pcr->rtd3_en)
> > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > -
> >       pcr->remove_pci = true;
> > +     if (pcr->rtd3_en) {
> > +             pm_runtime_get_sync(&pcidev->dev);
> > +             pm_runtime_forbid(&pcidev->dev);
> > +     }
> >
> >       /* Disable interrupts at the pcr level */
> >       spin_lock_irq(&pcr->lock);
> > @@ -1680,9 +1634,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
> >       spin_unlock_irq(&pcr->lock);
> >
> >       cancel_delayed_work_sync(&pcr->carddet_work);
> > -     cancel_delayed_work_sync(&pcr->idle_work);
> > -     if (pcr->rtd3_en)
> > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> >
> >       mfd_remove_devices(&pcidev->dev);
> >
> > @@ -1700,11 +1651,6 @@ static void rtsx_pci_remove(struct pci_dev
> > *pcidev)
> >       idr_remove(&rtsx_pci_idr, pcr->id);
> >       spin_unlock(&rtsx_pci_lock);
> >
> > -     if (pcr->rtd3_en) {
> > -             pm_runtime_disable(&pcr->pci->dev);
> > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > -     }
> > -
> >       kfree(pcr->slots);
> >       kfree(pcr);
> >       kfree(handle);
> > @@ -1726,7 +1672,6 @@ static int __maybe_unused rtsx_pci_suspend(struct
> > device *dev_d)
> >       pcr = handle->pcr;
> >
> >       cancel_delayed_work(&pcr->carddet_work);
> > -     cancel_delayed_work(&pcr->idle_work);
> >
> >       mutex_lock(&pcr->pcr_mutex);
> >
> > @@ -1760,8 +1705,6 @@ static int __maybe_unused rtsx_pci_resume(struct
> > device *dev_d)
> >       if (ret)
> >               goto out;
> >
> > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > -
> >  out:
> >       mutex_unlock(&pcr->pcr_mutex);
> >       return ret;
> > @@ -1786,6 +1729,32 @@ static void rtsx_pci_shutdown(struct pci_dev
> > *pcidev)
> >               pci_disable_msi(pcr->pci);
> >  }
> >
> > +static int rtsx_pci_runtime_idle(struct device *device) {
> > +     struct pci_dev *pcidev = to_pci_dev(device);
> > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > +     struct rtsx_pcr *pcr = handle->pcr;
> > +
> > +     dev_dbg(device, "--> %s\n", __func__);
> > +
> > +     mutex_lock(&pcr->pcr_mutex);
> > +
> > +     pcr->state = PDEV_STAT_IDLE;
> > +
> > +     if (pcr->ops->disable_auto_blink)
> > +             pcr->ops->disable_auto_blink(pcr);
> > +     if (pcr->ops->turn_off_led)
> > +             pcr->ops->turn_off_led(pcr);
> > +
> > +     rtsx_pm_power_saving(pcr);
> > +
> > +     mutex_unlock(&pcr->pcr_mutex);
> > +
> > +     pm_schedule_suspend(device, 5000);
> > +
> > +     return -EBUSY;
> > +}
> > +
> >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31 +1763,29 @@
> > static int rtsx_pci_runtime_suspend(struct device *device)
> >
> >       handle = pci_get_drvdata(pcidev);
> >       pcr = handle->pcr;
> > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> >
> > -     cancel_delayed_work(&pcr->carddet_work);
> > -     cancel_delayed_work(&pcr->rtd3_work);
> > -     cancel_delayed_work(&pcr->idle_work);
> > +     if (!pcr->rtd3_en)
> > +             return -EBUSY;
> > +
> > +     dev_dbg(device, "--> %s\n", __func__);
> > +
> > +     cancel_delayed_work_sync(&pcr->carddet_work);
> >
> >       mutex_lock(&pcr->pcr_mutex);
> >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> >
> >       mutex_unlock(&pcr->pcr_mutex);
> >
> > -     pcr->is_runtime_suspended = true;
> > -
> >       return 0;
> >  }
> >
> >  static int rtsx_pci_runtime_resume(struct device *device)  {
> >       struct pci_dev *pcidev = to_pci_dev(device);
> > -     struct pcr_handle *handle;
> > -     struct rtsx_pcr *pcr;
> > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > +     struct rtsx_pcr *pcr = handle->pcr;
> >
> > -     handle = pci_get_drvdata(pcidev);
> > -     pcr = handle->pcr;
> > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > +     dev_dbg(device, "--> %s\n", __func__);
> >
> >       mutex_lock(&pcr->pcr_mutex);
> >
> > @@ -1834,8 +1801,6 @@ static int rtsx_pci_runtime_resume(struct device
> > *device)
> >                               pcr->slots[RTSX_SD_CARD].p_dev);
> >       }
> >
> > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > -
> >       mutex_unlock(&pcr->pcr_mutex);
> >       return 0;
> >  }
> > @@ -1850,7 +1815,7 @@ static int rtsx_pci_runtime_resume(struct device
> > *device)
> >
> >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > rtsx_pci_runtime_resume, NULL)
> > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > rtsx_pci_runtime_resume,
> > +rtsx_pci_runtime_idle)
> >  };
> >
> >  static struct pci_driver rtsx_pci_driver = { diff --git a/include/linux/rtsx_pci.h
> > b/include/linux/rtsx_pci.h index 4ab7bfc675f11..89b7d34e25b63 100644
> > --- a/include/linux/rtsx_pci.h
> > +++ b/include/linux/rtsx_pci.h
> > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> >       unsigned int                    card_exist;
> >
> >       struct delayed_work             carddet_work;
> > -     struct delayed_work             idle_work;
> > -     struct delayed_work             rtd3_work;
> >
> >       spinlock_t                      lock;
> >       struct mutex                    pcr_mutex;
> > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> >       unsigned int                    cur_clock;
> >       bool                            remove_pci;
> >       bool                            msi_en;
> > -     bool                            is_runtime_suspended;
> >
> >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > --
> > 2.33.1
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  4:08       ` Kai-Heng Feng
@ 2022-01-21  4:15         ` Ricky WU
  2022-01-21  4:17           ` Kai-Heng Feng
  0 siblings, 1 reply; 35+ messages in thread
From: Ricky WU @ 2022-01-21  4:15 UTC (permalink / raw)
  To: Kai-Heng Feng
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Friday, January 21, 2022 12:08 PM
> To: Ricky WU <ricky_wu@realtek.com>
> Cc: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org;
> linux-pm@vger.kernel.org; Christophe JAILLET
> <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v2 2/4] misc: rtsx: Rework runtime power management
> flow
> 
> On Fri, Jan 21, 2022 at 11:57 AM Ricky WU <ricky_wu@realtek.com> wrote:
> >
> > > -----Original Message-----
> > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > Sent: Friday, January 21, 2022 9:41 AM
> > > To: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > ulf.hansson@linaro.org
> > > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng
> > > <kai.heng.feng@canonical.com>; Ricky WU <ricky_wu@realtek.com>;
> > > Christophe JAILLET <christophe.jaillet@wanadoo.fr>; Yang Li
> > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > Subject: [PATCH v2 2/4] misc: rtsx: Rework runtime power management
> > > flow
> > >
> > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> > > "rtd3_work" and "idle_work" to manage it's own runtime PM state
> machine.
> > >
> > > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
> > > correctly, all the additional works can be managed by generic runtime PM
> helpers.
> > >
> > > So consolidate "idle_work" and "rtd3_work" into generic runtime idle
> > > callback and runtime suspend callback, respectively.
> > >
> >
> > This idle_work is not runtime_idle, this is for aspm setting Not only
> > for support RPM, so this idle_work can not be remove....
> 
> rtsx_pm_power_saving() is called inside rtsx_pci_runtime_idle(), when the
> usage refcount becomes zero, before runtime suspend routine.
> 
> >
> > Our original Idle_work is a power saveing function, It is a delay_work
> > for 200 msec  , If no work comes in 200 msec than go to idle_work to set
> power saveing setting.....
> 
> Have you tested it locally? rtsx_pci_runtime_idle() really does the same thing.
> 

We are testing...
RTD3 is not available on all platforms....
We use a values (rtd3_en) to judge rtd3 enable or not

Aspm is for all platform but RTD3 is not 

> 
> >
> > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > ---
> > > v2:
> > >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> > >
> > >  drivers/misc/cardreader/rtsx_pcr.c | 123 +++++++++++------------------
> > >  include/linux/rtsx_pci.h           |   3 -
> > >  2 files changed, 44 insertions(+), 82 deletions(-)
> > >
> > > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > > b/drivers/misc/cardreader/rtsx_pcr.c
> > > index 6ac509c1821c9..1dcf98b597569 100644
> > > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> > >       if (pcr->remove_pci)
> > >               return;
> > >
> > > -     if (pcr->rtd3_en)
> > > -             if (pcr->is_runtime_suspended) {
> > > -                     pm_runtime_get(&(pcr->pci->dev));
> > > -                     pcr->is_runtime_suspended = false;
> > > -             }
> > > -
> > >       if (pcr->state != PDEV_STAT_RUN) {
> > >               pcr->state = PDEV_STAT_RUN;
> > >               if (pcr->ops->enable_auto_blink)
> > >                       pcr->ops->enable_auto_blink(pcr);
> > >               rtsx_pm_full_on(pcr);
> > >       }
> > > -
> > > -     mod_delayed_work(system_wq, &pcr->idle_work,
> msecs_to_jiffies(200));
> > >  }
> > >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> > >
> > > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct
> > > rtsx_pcr
> > > *pcr)
> > >       rtsx_comm_pm_power_saving(pcr);  }
> > >
> > > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> rtd3_work);
> > > -
> > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > -     if (!pcr->is_runtime_suspended)
> > > -             pm_runtime_put(&(pcr->pci->dev));
> > > -}
> > > -
> > > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> idle_work);
> > > -
> > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > -
> > > -     mutex_lock(&pcr->pcr_mutex);
> > > -
> > > -     pcr->state = PDEV_STAT_IDLE;
> > > -
> > > -     if (pcr->ops->disable_auto_blink)
> > > -             pcr->ops->disable_auto_blink(pcr);
> > > -     if (pcr->ops->turn_off_led)
> > > -             pcr->ops->turn_off_led(pcr);
> > > -
> > > -     rtsx_pm_power_saving(pcr);
> > > -
> > > -     mutex_unlock(&pcr->pcr_mutex);
> > > -
> > > -     if (pcr->rtd3_en)
> > > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > > msecs_to_jiffies(10000));
> > > -}
> > > -
> > >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8
> > > pm_state) {
> > >       /* Set relink_time to 0 */
> > > @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> > >       pcr->card_inserted = 0;
> > >       pcr->card_removed = 0;
> > >       INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> > > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> > >
> > >       pcr->msi_en = msi_en;
> > >       if (pcr->msi_en) {
> > > @@ -1623,20 +1580,16 @@ static int rtsx_pci_probe(struct pci_dev
> *pcidev,
> > >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> > >       }
> > >
> > > -     if (pcr->rtd3_en) {
> > > -             INIT_DELAYED_WORK(&pcr->rtd3_work,
> rtsx_pci_rtd3_work);
> > > -             pm_runtime_allow(&pcidev->dev);
> > > -             pm_runtime_enable(&pcidev->dev);
> > > -             pcr->is_runtime_suspended = false;
> > > -     }
> > > -
> > >
> > >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> > >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
> > >       if (ret < 0)
> > >               goto free_slots;
> > >
> > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > +     if (pcr->rtd3_en) {
> > > +             pm_runtime_allow(&pcidev->dev);
> > > +             pm_runtime_put(&pcidev->dev);
> > > +     }
> > >
> > >       return 0;
> > >
> > > @@ -1668,10 +1621,11 @@ static void rtsx_pci_remove(struct pci_dev
> > > *pcidev)
> > >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > >       struct rtsx_pcr *pcr = handle->pcr;
> > >
> > > -     if (pcr->rtd3_en)
> > > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > > -
> > >       pcr->remove_pci = true;
> > > +     if (pcr->rtd3_en) {
> > > +             pm_runtime_get_sync(&pcidev->dev);
> > > +             pm_runtime_forbid(&pcidev->dev);
> > > +     }
> > >
> > >       /* Disable interrupts at the pcr level */
> > >       spin_lock_irq(&pcr->lock);
> > > @@ -1680,9 +1634,6 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
> > >       spin_unlock_irq(&pcr->lock);
> > >
> > >       cancel_delayed_work_sync(&pcr->carddet_work);
> > > -     cancel_delayed_work_sync(&pcr->idle_work);
> > > -     if (pcr->rtd3_en)
> > > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> > >
> > >       mfd_remove_devices(&pcidev->dev);
> > >
> > > @@ -1700,11 +1651,6 @@ static void rtsx_pci_remove(struct pci_dev
> > > *pcidev)
> > >       idr_remove(&rtsx_pci_idr, pcr->id);
> > >       spin_unlock(&rtsx_pci_lock);
> > >
> > > -     if (pcr->rtd3_en) {
> > > -             pm_runtime_disable(&pcr->pci->dev);
> > > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > > -     }
> > > -
> > >       kfree(pcr->slots);
> > >       kfree(pcr);
> > >       kfree(handle);
> > > @@ -1726,7 +1672,6 @@ static int __maybe_unused
> > > rtsx_pci_suspend(struct device *dev_d)
> > >       pcr = handle->pcr;
> > >
> > >       cancel_delayed_work(&pcr->carddet_work);
> > > -     cancel_delayed_work(&pcr->idle_work);
> > >
> > >       mutex_lock(&pcr->pcr_mutex);
> > >
> > > @@ -1760,8 +1705,6 @@ static int __maybe_unused
> > > rtsx_pci_resume(struct device *dev_d)
> > >       if (ret)
> > >               goto out;
> > >
> > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > -
> > >  out:
> > >       mutex_unlock(&pcr->pcr_mutex);
> > >       return ret;
> > > @@ -1786,6 +1729,32 @@ static void rtsx_pci_shutdown(struct pci_dev
> > > *pcidev)
> > >               pci_disable_msi(pcr->pci);  }
> > >
> > > +static int rtsx_pci_runtime_idle(struct device *device) {
> > > +     struct pci_dev *pcidev = to_pci_dev(device);
> > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > +
> > > +     dev_dbg(device, "--> %s\n", __func__);
> > > +
> > > +     mutex_lock(&pcr->pcr_mutex);
> > > +
> > > +     pcr->state = PDEV_STAT_IDLE;
> > > +
> > > +     if (pcr->ops->disable_auto_blink)
> > > +             pcr->ops->disable_auto_blink(pcr);
> > > +     if (pcr->ops->turn_off_led)
> > > +             pcr->ops->turn_off_led(pcr);
> > > +
> > > +     rtsx_pm_power_saving(pcr);
> > > +
> > > +     mutex_unlock(&pcr->pcr_mutex);
> > > +
> > > +     pm_schedule_suspend(device, 5000);
> > > +
> > > +     return -EBUSY;
> > > +}
> > > +
> > >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> > >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31
> > > +1763,29 @@ static int rtsx_pci_runtime_suspend(struct device
> > > *device)
> > >
> > >       handle = pci_get_drvdata(pcidev);
> > >       pcr = handle->pcr;
> > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > >
> > > -     cancel_delayed_work(&pcr->carddet_work);
> > > -     cancel_delayed_work(&pcr->rtd3_work);
> > > -     cancel_delayed_work(&pcr->idle_work);
> > > +     if (!pcr->rtd3_en)
> > > +             return -EBUSY;
> > > +
> > > +     dev_dbg(device, "--> %s\n", __func__);
> > > +
> > > +     cancel_delayed_work_sync(&pcr->carddet_work);
> > >
> > >       mutex_lock(&pcr->pcr_mutex);
> > >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> > >
> > >       mutex_unlock(&pcr->pcr_mutex);
> > >
> > > -     pcr->is_runtime_suspended = true;
> > > -
> > >       return 0;
> > >  }
> > >
> > >  static int rtsx_pci_runtime_resume(struct device *device)  {
> > >       struct pci_dev *pcidev = to_pci_dev(device);
> > > -     struct pcr_handle *handle;
> > > -     struct rtsx_pcr *pcr;
> > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > +     struct rtsx_pcr *pcr = handle->pcr;
> > >
> > > -     handle = pci_get_drvdata(pcidev);
> > > -     pcr = handle->pcr;
> > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > +     dev_dbg(device, "--> %s\n", __func__);
> > >
> > >       mutex_lock(&pcr->pcr_mutex);
> > >
> > > @@ -1834,8 +1801,6 @@ static int rtsx_pci_runtime_resume(struct
> > > device
> > > *device)
> > >                               pcr->slots[RTSX_SD_CARD].p_dev);
> > >       }
> > >
> > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > -
> > >       mutex_unlock(&pcr->pcr_mutex);
> > >       return 0;
> > >  }
> > > @@ -1850,7 +1815,7 @@ static int rtsx_pci_runtime_resume(struct
> > > device
> > > *device)
> > >
> > >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> > >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> > > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > rtsx_pci_runtime_resume, NULL)
> > > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > rtsx_pci_runtime_resume,
> > > +rtsx_pci_runtime_idle)
> > >  };
> > >
> > >  static struct pci_driver rtsx_pci_driver = { diff --git
> > > a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> > > 4ab7bfc675f11..89b7d34e25b63 100644
> > > --- a/include/linux/rtsx_pci.h
> > > +++ b/include/linux/rtsx_pci.h
> > > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> > >       unsigned int                    card_exist;
> > >
> > >       struct delayed_work             carddet_work;
> > > -     struct delayed_work             idle_work;
> > > -     struct delayed_work             rtd3_work;
> > >
> > >       spinlock_t                      lock;
> > >       struct mutex                    pcr_mutex;
> > > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> > >       unsigned int                    cur_clock;
> > >       bool                            remove_pci;
> > >       bool                            msi_en;
> > > -     bool                            is_runtime_suspended;
> > >
> > >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> > >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > > --
> > > 2.33.1
> >
> ------Please consider the environment before printing this e-mail.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  4:15         ` Ricky WU
@ 2022-01-21  4:17           ` Kai-Heng Feng
  0 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-21  4:17 UTC (permalink / raw)
  To: Ricky WU
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

On Fri, Jan 21, 2022 at 12:15 PM Ricky WU <ricky_wu@realtek.com> wrote:
>
> > -----Original Message-----
> > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > Sent: Friday, January 21, 2022 12:08 PM
> > To: Ricky WU <ricky_wu@realtek.com>
> > Cc: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org;
> > linux-pm@vger.kernel.org; Christophe JAILLET
> > <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> > linux-kernel@vger.kernel.org
> > Subject: Re: [PATCH v2 2/4] misc: rtsx: Rework runtime power management
> > flow
> >
> > On Fri, Jan 21, 2022 at 11:57 AM Ricky WU <ricky_wu@realtek.com> wrote:
> > >
> > > > -----Original Message-----
> > > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > Sent: Friday, January 21, 2022 9:41 AM
> > > > To: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > > ulf.hansson@linaro.org
> > > > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng
> > > > <kai.heng.feng@canonical.com>; Ricky WU <ricky_wu@realtek.com>;
> > > > Christophe JAILLET <christophe.jaillet@wanadoo.fr>; Yang Li
> > > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > > Subject: [PATCH v2 2/4] misc: rtsx: Rework runtime power management
> > > > flow
> > > >
> > > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> > > > "rtd3_work" and "idle_work" to manage it's own runtime PM state
> > machine.
> > > >
> > > > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
> > > > correctly, all the additional works can be managed by generic runtime PM
> > helpers.
> > > >
> > > > So consolidate "idle_work" and "rtd3_work" into generic runtime idle
> > > > callback and runtime suspend callback, respectively.
> > > >
> > >
> > > This idle_work is not runtime_idle, this is for aspm setting Not only
> > > for support RPM, so this idle_work can not be remove....
> >
> > rtsx_pm_power_saving() is called inside rtsx_pci_runtime_idle(), when the
> > usage refcount becomes zero, before runtime suspend routine.
> >
> > >
> > > Our original Idle_work is a power saveing function, It is a delay_work
> > > for 200 msec  , If no work comes in 200 msec than go to idle_work to set
> > power saveing setting.....
> >
> > Have you tested it locally? rtsx_pci_runtime_idle() really does the same thing.
> >
>
> We are testing...
> RTD3 is not available on all platforms....
> We use a values (rtd3_en) to judge rtd3 enable or not
>
> Aspm is for all platform but RTD3 is not

Thanks! I get it now.
Let me send v3 to address the issue.

Kai-Heng

>
> >
> > >
> > > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > ---
> > > > v2:
> > > >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> > > >
> > > >  drivers/misc/cardreader/rtsx_pcr.c | 123 +++++++++++------------------
> > > >  include/linux/rtsx_pci.h           |   3 -
> > > >  2 files changed, 44 insertions(+), 82 deletions(-)
> > > >
> > > > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > > > b/drivers/misc/cardreader/rtsx_pcr.c
> > > > index 6ac509c1821c9..1dcf98b597569 100644
> > > > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > > > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > > > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> > > >       if (pcr->remove_pci)
> > > >               return;
> > > >
> > > > -     if (pcr->rtd3_en)
> > > > -             if (pcr->is_runtime_suspended) {
> > > > -                     pm_runtime_get(&(pcr->pci->dev));
> > > > -                     pcr->is_runtime_suspended = false;
> > > > -             }
> > > > -
> > > >       if (pcr->state != PDEV_STAT_RUN) {
> > > >               pcr->state = PDEV_STAT_RUN;
> > > >               if (pcr->ops->enable_auto_blink)
> > > >                       pcr->ops->enable_auto_blink(pcr);
> > > >               rtsx_pm_full_on(pcr);
> > > >       }
> > > > -
> > > > -     mod_delayed_work(system_wq, &pcr->idle_work,
> > msecs_to_jiffies(200));
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> > > >
> > > > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct
> > > > rtsx_pcr
> > > > *pcr)
> > > >       rtsx_comm_pm_power_saving(pcr);  }
> > > >
> > > > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > rtd3_work);
> > > > -
> > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > -     if (!pcr->is_runtime_suspended)
> > > > -             pm_runtime_put(&(pcr->pci->dev));
> > > > -}
> > > > -
> > > > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > idle_work);
> > > > -
> > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > -
> > > > -     mutex_lock(&pcr->pcr_mutex);
> > > > -
> > > > -     pcr->state = PDEV_STAT_IDLE;
> > > > -
> > > > -     if (pcr->ops->disable_auto_blink)
> > > > -             pcr->ops->disable_auto_blink(pcr);
> > > > -     if (pcr->ops->turn_off_led)
> > > > -             pcr->ops->turn_off_led(pcr);
> > > > -
> > > > -     rtsx_pm_power_saving(pcr);
> > > > -
> > > > -     mutex_unlock(&pcr->pcr_mutex);
> > > > -
> > > > -     if (pcr->rtd3_en)
> > > > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > > > msecs_to_jiffies(10000));
> > > > -}
> > > > -
> > > >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8
> > > > pm_state) {
> > > >       /* Set relink_time to 0 */
> > > > @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> > > >       pcr->card_inserted = 0;
> > > >       pcr->card_removed = 0;
> > > >       INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> > > > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> > > >
> > > >       pcr->msi_en = msi_en;
> > > >       if (pcr->msi_en) {
> > > > @@ -1623,20 +1580,16 @@ static int rtsx_pci_probe(struct pci_dev
> > *pcidev,
> > > >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> > > >       }
> > > >
> > > > -     if (pcr->rtd3_en) {
> > > > -             INIT_DELAYED_WORK(&pcr->rtd3_work,
> > rtsx_pci_rtd3_work);
> > > > -             pm_runtime_allow(&pcidev->dev);
> > > > -             pm_runtime_enable(&pcidev->dev);
> > > > -             pcr->is_runtime_suspended = false;
> > > > -     }
> > > > -
> > > >
> > > >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> > > >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
> > > >       if (ret < 0)
> > > >               goto free_slots;
> > > >
> > > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > > +     if (pcr->rtd3_en) {
> > > > +             pm_runtime_allow(&pcidev->dev);
> > > > +             pm_runtime_put(&pcidev->dev);
> > > > +     }
> > > >
> > > >       return 0;
> > > >
> > > > @@ -1668,10 +1621,11 @@ static void rtsx_pci_remove(struct pci_dev
> > > > *pcidev)
> > > >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > >       struct rtsx_pcr *pcr = handle->pcr;
> > > >
> > > > -     if (pcr->rtd3_en)
> > > > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > > > -
> > > >       pcr->remove_pci = true;
> > > > +     if (pcr->rtd3_en) {
> > > > +             pm_runtime_get_sync(&pcidev->dev);
> > > > +             pm_runtime_forbid(&pcidev->dev);
> > > > +     }
> > > >
> > > >       /* Disable interrupts at the pcr level */
> > > >       spin_lock_irq(&pcr->lock);
> > > > @@ -1680,9 +1634,6 @@ static void rtsx_pci_remove(struct pci_dev
> > *pcidev)
> > > >       spin_unlock_irq(&pcr->lock);
> > > >
> > > >       cancel_delayed_work_sync(&pcr->carddet_work);
> > > > -     cancel_delayed_work_sync(&pcr->idle_work);
> > > > -     if (pcr->rtd3_en)
> > > > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> > > >
> > > >       mfd_remove_devices(&pcidev->dev);
> > > >
> > > > @@ -1700,11 +1651,6 @@ static void rtsx_pci_remove(struct pci_dev
> > > > *pcidev)
> > > >       idr_remove(&rtsx_pci_idr, pcr->id);
> > > >       spin_unlock(&rtsx_pci_lock);
> > > >
> > > > -     if (pcr->rtd3_en) {
> > > > -             pm_runtime_disable(&pcr->pci->dev);
> > > > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > > > -     }
> > > > -
> > > >       kfree(pcr->slots);
> > > >       kfree(pcr);
> > > >       kfree(handle);
> > > > @@ -1726,7 +1672,6 @@ static int __maybe_unused
> > > > rtsx_pci_suspend(struct device *dev_d)
> > > >       pcr = handle->pcr;
> > > >
> > > >       cancel_delayed_work(&pcr->carddet_work);
> > > > -     cancel_delayed_work(&pcr->idle_work);
> > > >
> > > >       mutex_lock(&pcr->pcr_mutex);
> > > >
> > > > @@ -1760,8 +1705,6 @@ static int __maybe_unused
> > > > rtsx_pci_resume(struct device *dev_d)
> > > >       if (ret)
> > > >               goto out;
> > > >
> > > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > > -
> > > >  out:
> > > >       mutex_unlock(&pcr->pcr_mutex);
> > > >       return ret;
> > > > @@ -1786,6 +1729,32 @@ static void rtsx_pci_shutdown(struct pci_dev
> > > > *pcidev)
> > > >               pci_disable_msi(pcr->pci);  }
> > > >
> > > > +static int rtsx_pci_runtime_idle(struct device *device) {
> > > > +     struct pci_dev *pcidev = to_pci_dev(device);
> > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > > +
> > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > +
> > > > +     mutex_lock(&pcr->pcr_mutex);
> > > > +
> > > > +     pcr->state = PDEV_STAT_IDLE;
> > > > +
> > > > +     if (pcr->ops->disable_auto_blink)
> > > > +             pcr->ops->disable_auto_blink(pcr);
> > > > +     if (pcr->ops->turn_off_led)
> > > > +             pcr->ops->turn_off_led(pcr);
> > > > +
> > > > +     rtsx_pm_power_saving(pcr);
> > > > +
> > > > +     mutex_unlock(&pcr->pcr_mutex);
> > > > +
> > > > +     pm_schedule_suspend(device, 5000);
> > > > +
> > > > +     return -EBUSY;
> > > > +}
> > > > +
> > > >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> > > >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31
> > > > +1763,29 @@ static int rtsx_pci_runtime_suspend(struct device
> > > > *device)
> > > >
> > > >       handle = pci_get_drvdata(pcidev);
> > > >       pcr = handle->pcr;
> > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > >
> > > > -     cancel_delayed_work(&pcr->carddet_work);
> > > > -     cancel_delayed_work(&pcr->rtd3_work);
> > > > -     cancel_delayed_work(&pcr->idle_work);
> > > > +     if (!pcr->rtd3_en)
> > > > +             return -EBUSY;
> > > > +
> > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > +
> > > > +     cancel_delayed_work_sync(&pcr->carddet_work);
> > > >
> > > >       mutex_lock(&pcr->pcr_mutex);
> > > >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> > > >
> > > >       mutex_unlock(&pcr->pcr_mutex);
> > > >
> > > > -     pcr->is_runtime_suspended = true;
> > > > -
> > > >       return 0;
> > > >  }
> > > >
> > > >  static int rtsx_pci_runtime_resume(struct device *device)  {
> > > >       struct pci_dev *pcidev = to_pci_dev(device);
> > > > -     struct pcr_handle *handle;
> > > > -     struct rtsx_pcr *pcr;
> > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > >
> > > > -     handle = pci_get_drvdata(pcidev);
> > > > -     pcr = handle->pcr;
> > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > >
> > > >       mutex_lock(&pcr->pcr_mutex);
> > > >
> > > > @@ -1834,8 +1801,6 @@ static int rtsx_pci_runtime_resume(struct
> > > > device
> > > > *device)
> > > >                               pcr->slots[RTSX_SD_CARD].p_dev);
> > > >       }
> > > >
> > > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > > -
> > > >       mutex_unlock(&pcr->pcr_mutex);
> > > >       return 0;
> > > >  }
> > > > @@ -1850,7 +1815,7 @@ static int rtsx_pci_runtime_resume(struct
> > > > device
> > > > *device)
> > > >
> > > >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> > > >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> > > > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > rtsx_pci_runtime_resume, NULL)
> > > > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > rtsx_pci_runtime_resume,
> > > > +rtsx_pci_runtime_idle)
> > > >  };
> > > >
> > > >  static struct pci_driver rtsx_pci_driver = { diff --git
> > > > a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> > > > 4ab7bfc675f11..89b7d34e25b63 100644
> > > > --- a/include/linux/rtsx_pci.h
> > > > +++ b/include/linux/rtsx_pci.h
> > > > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> > > >       unsigned int                    card_exist;
> > > >
> > > >       struct delayed_work             carddet_work;
> > > > -     struct delayed_work             idle_work;
> > > > -     struct delayed_work             rtd3_work;
> > > >
> > > >       spinlock_t                      lock;
> > > >       struct mutex                    pcr_mutex;
> > > > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> > > >       unsigned int                    cur_clock;
> > > >       bool                            remove_pci;
> > > >       bool                            msi_en;
> > > > -     bool                            is_runtime_suspended;
> > > >
> > > >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> > > >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > > > --
> > > > 2.33.1
> > >
> > ------Please consider the environment before printing this e-mail.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
  2022-01-21  3:57     ` Ricky WU
@ 2022-01-21  6:31     ` Kai-Heng Feng
  2022-01-21  9:58       ` Ricky WU
  2022-01-24  5:47     ` [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-21  6:31 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
uses "rtd3_work" and "idle_work" to manage it's own runtime PM state
machine.

When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
correctly, all the additional works can be managed by generic runtime PM
helpers.

So consolidate "idle_work" and "rtd3_work" into generic runtime idle
callback and runtime suspend callback, respectively.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v3:
 - Allow runtime PM for all devices, but only schedule runtime suspend
   for devices with rtd3_en flagged.

v2:
 - Remove unused idle_work and rtd3_work from rtsx_pcr.

 drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
 include/linux/rtsx_pci.h           |   3 -
 2 files changed, 39 insertions(+), 82 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 6ac509c1821c9..f919290f01192 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
 	if (pcr->remove_pci)
 		return;
 
-	if (pcr->rtd3_en)
-		if (pcr->is_runtime_suspended) {
-			pm_runtime_get(&(pcr->pci->dev));
-			pcr->is_runtime_suspended = false;
-		}
-
 	if (pcr->state != PDEV_STAT_RUN) {
 		pcr->state = PDEV_STAT_RUN;
 		if (pcr->ops->enable_auto_blink)
 			pcr->ops->enable_auto_blink(pcr);
 		rtsx_pm_full_on(pcr);
 	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-	if (!pcr->is_runtime_suspended)
-		pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if (pcr->rtd3_en)
-		mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
 static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 {
 	/* Set relink_time to 0 */
@@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 	pcr->card_inserted = 0;
 	pcr->card_removed = 0;
 	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
 	pcr->msi_en = msi_en;
 	if (pcr->msi_en) {
@@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
 	}
 
-	if (pcr->rtd3_en) {
-		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-		pm_runtime_allow(&pcidev->dev);
-		pm_runtime_enable(&pcidev->dev);
-		pcr->is_runtime_suspended = false;
-	}
-
 
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
 		goto free_slots;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+	pm_runtime_allow(&pcidev->dev);
+	pm_runtime_put(&pcidev->dev);
 
 	return 0;
 
@@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	struct pcr_handle *handle = pci_get_drvdata(pcidev);
 	struct rtsx_pcr *pcr = handle->pcr;
 
-	if (pcr->rtd3_en)
-		pm_runtime_get_noresume(&pcr->pci->dev);
-
 	pcr->remove_pci = true;
 
+	pm_runtime_get_sync(&pcidev->dev);
+	pm_runtime_forbid(&pcidev->dev);
+
 	/* Disable interrupts at the pcr level */
 	spin_lock_irq(&pcr->lock);
 	rtsx_pci_writel(pcr, RTSX_BIER, 0);
@@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	spin_unlock_irq(&pcr->lock);
 
 	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-	if (pcr->rtd3_en)
-		cancel_delayed_work_sync(&pcr->rtd3_work);
 
 	mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	idr_remove(&rtsx_pci_idr, pcr->id);
 	spin_unlock(&rtsx_pci_lock);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_disable(&pcr->pci->dev);
-		pm_runtime_put_noidle(&pcr->pci->dev);
-	}
-
 	kfree(pcr->slots);
 	kfree(pcr);
 	kfree(handle);
@@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	pcr = handle->pcr;
 
 	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 	if (ret)
 		goto out;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
 	mutex_unlock(&pcr->pcr_mutex);
 	return ret;
@@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 		pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+	struct pci_dev *pcidev = to_pci_dev(device);
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	if (pcr->rtd3_en)
+		pm_schedule_suspend(device, 5000);
+
+	return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
@@ -1794,31 +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->rtd3_work);
-	cancel_delayed_work(&pcr->idle_work);
+	dev_dbg(device, "--> %s\n", __func__);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
-	pcr->is_runtime_suspended = true;
-
 	return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+	dev_dbg(device, "--> %s\n", __func__);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 				pcr->slots[RTSX_SD_CARD].p_dev);
 	}
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 4ab7bfc675f11..89b7d34e25b63 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1201,8 +1201,6 @@ struct rtsx_pcr {
 	unsigned int			card_exist;
 
 	struct delayed_work		carddet_work;
-	struct delayed_work		idle_work;
-	struct delayed_work		rtd3_work;
 
 	spinlock_t			lock;
 	struct mutex			pcr_mutex;
@@ -1212,7 +1210,6 @@ struct rtsx_pcr {
 	unsigned int			cur_clock;
 	bool				remove_pci;
 	bool				msi_en;
-	bool				is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50		(1 << 0)
 #define EXTRA_CAPS_SD_SDR104		(1 << 1)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* RE: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  6:31     ` [PATCH v3 " Kai-Heng Feng
@ 2022-01-21  9:58       ` Ricky WU
  2022-01-21 12:39         ` Kai-Heng Feng
  0 siblings, 1 reply; 35+ messages in thread
From: Ricky WU @ 2022-01-21  9:58 UTC (permalink / raw)
  To: Kai-Heng Feng, arnd, gregkh, ulf.hansson
  Cc: linux-pm, Christophe JAILLET, Yang Li, linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Friday, January 21, 2022 2:32 PM
> To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> Ricky WU <ricky_wu@realtek.com>; Christophe JAILLET
> <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> linux-kernel@vger.kernel.org
> Subject: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
> 
> Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> "rtd3_work" and "idle_work" to manage it's own runtime PM state machine.
> 
> When its child device, rtsx_pci_sdmmc, uses runtime PM refcount correctly, all
> the additional works can be managed by generic runtime PM helpers.
> 
> So consolidate "idle_work" and "rtd3_work" into generic runtime idle callback
> and runtime suspend callback, respectively.


Original idle_work is for aspm delay time is 200 msec, because Aspm can quick in and out to save more power
Now this patch need to wait 5 sec because set autosuspend time set to 5 sec in sdmmc,... this time need to set to 200 msec.

But it will get another question, the question is the host(sdmmc) caps has set MMC_CAP_AGGRESSIVE_PM when rtd3_en is set,
It will make card power off when sdmmc go to suspend, 200 msec will cause card power off and on frequently

Need to remove this flag in caps, and then change card power off to rtsx_pci_runtime_suspend()....

What do you think?

Ricky

> 
> Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> Cc: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v3:
>  - Allow runtime PM for all devices, but only schedule runtime suspend
>    for devices with rtd3_en flagged.
> 
> v2:
>  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> 
>  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
>  include/linux/rtsx_pci.h           |   3 -
>  2 files changed, 39 insertions(+), 82 deletions(-)
> 
> diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> b/drivers/misc/cardreader/rtsx_pcr.c
> index 6ac509c1821c9..f919290f01192 100644
> --- a/drivers/misc/cardreader/rtsx_pcr.c
> +++ b/drivers/misc/cardreader/rtsx_pcr.c
> @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
>  	if (pcr->remove_pci)
>  		return;
> 
> -	if (pcr->rtd3_en)
> -		if (pcr->is_runtime_suspended) {
> -			pm_runtime_get(&(pcr->pci->dev));
> -			pcr->is_runtime_suspended = false;
> -		}
> -
>  	if (pcr->state != PDEV_STAT_RUN) {
>  		pcr->state = PDEV_STAT_RUN;
>  		if (pcr->ops->enable_auto_blink)
>  			pcr->ops->enable_auto_blink(pcr);
>  		rtsx_pm_full_on(pcr);
>  	}
> -
> -	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
>  }
>  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> 
> @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr
> *pcr)
>  	rtsx_comm_pm_power_saving(pcr);
>  }
> 
> -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> -	struct delayed_work *dwork = to_delayed_work(work);
> -	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
> -
> -	pcr_dbg(pcr, "--> %s\n", __func__);
> -	if (!pcr->is_runtime_suspended)
> -		pm_runtime_put(&(pcr->pci->dev));
> -}
> -
> -static void rtsx_pci_idle_work(struct work_struct *work) -{
> -	struct delayed_work *dwork = to_delayed_work(work);
> -	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
> -
> -	pcr_dbg(pcr, "--> %s\n", __func__);
> -
> -	mutex_lock(&pcr->pcr_mutex);
> -
> -	pcr->state = PDEV_STAT_IDLE;
> -
> -	if (pcr->ops->disable_auto_blink)
> -		pcr->ops->disable_auto_blink(pcr);
> -	if (pcr->ops->turn_off_led)
> -		pcr->ops->turn_off_led(pcr);
> -
> -	rtsx_pm_power_saving(pcr);
> -
> -	mutex_unlock(&pcr->pcr_mutex);
> -
> -	if (pcr->rtd3_en)
> -		mod_delayed_work(system_wq, &pcr->rtd3_work,
> msecs_to_jiffies(10000));
> -}
> -
>  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> {
>  	/* Set relink_time to 0 */
> @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
>  	pcr->card_inserted = 0;
>  	pcr->card_removed = 0;
>  	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> -	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> 
>  	pcr->msi_en = msi_en;
>  	if (pcr->msi_en) {
> @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
>  		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
>  	}
> 
> -	if (pcr->rtd3_en) {
> -		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
> -		pm_runtime_allow(&pcidev->dev);
> -		pm_runtime_enable(&pcidev->dev);
> -		pcr->is_runtime_suspended = false;
> -	}
> -
> 
>  	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
>  			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
>  	if (ret < 0)
>  		goto free_slots;
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> +	pm_runtime_allow(&pcidev->dev);
> +	pm_runtime_put(&pcidev->dev);
> 
>  	return 0;
> 
> @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
>  	struct pcr_handle *handle = pci_get_drvdata(pcidev);
>  	struct rtsx_pcr *pcr = handle->pcr;
> 
> -	if (pcr->rtd3_en)
> -		pm_runtime_get_noresume(&pcr->pci->dev);
> -
>  	pcr->remove_pci = true;
> 
> +	pm_runtime_get_sync(&pcidev->dev);
> +	pm_runtime_forbid(&pcidev->dev);
> +
>  	/* Disable interrupts at the pcr level */
>  	spin_lock_irq(&pcr->lock);
>  	rtsx_pci_writel(pcr, RTSX_BIER, 0);
> @@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
>  	spin_unlock_irq(&pcr->lock);
> 
>  	cancel_delayed_work_sync(&pcr->carddet_work);
> -	cancel_delayed_work_sync(&pcr->idle_work);
> -	if (pcr->rtd3_en)
> -		cancel_delayed_work_sync(&pcr->rtd3_work);
> 
>  	mfd_remove_devices(&pcidev->dev);
> 
> @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
>  	idr_remove(&rtsx_pci_idr, pcr->id);
>  	spin_unlock(&rtsx_pci_lock);
> 
> -	if (pcr->rtd3_en) {
> -		pm_runtime_disable(&pcr->pci->dev);
> -		pm_runtime_put_noidle(&pcr->pci->dev);
> -	}
> -
>  	kfree(pcr->slots);
>  	kfree(pcr);
>  	kfree(handle);
> @@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct
> device *dev_d)
>  	pcr = handle->pcr;
> 
>  	cancel_delayed_work(&pcr->carddet_work);
> -	cancel_delayed_work(&pcr->idle_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> @@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct
> device *dev_d)
>  	if (ret)
>  		goto out;
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> -
>  out:
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return ret;
> @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev
> *pcidev)
>  		pci_disable_msi(pcr->pci);
>  }
> 
> +static int rtsx_pci_runtime_idle(struct device *device) {
> +	struct pci_dev *pcidev = to_pci_dev(device);
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> +
> +	dev_dbg(device, "--> %s\n", __func__);
> +
> +	mutex_lock(&pcr->pcr_mutex);
> +
> +	pcr->state = PDEV_STAT_IDLE;
> +
> +	if (pcr->ops->disable_auto_blink)
> +		pcr->ops->disable_auto_blink(pcr);
> +	if (pcr->ops->turn_off_led)
> +		pcr->ops->turn_off_led(pcr);
> +
> +	rtsx_pm_power_saving(pcr);
> +
> +	mutex_unlock(&pcr->pcr_mutex);
> +
> +	if (pcr->rtd3_en)
> +		pm_schedule_suspend(device, 5000);
> +
> +	return -EBUSY;
> +}
> +
>  static int rtsx_pci_runtime_suspend(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31 +1761,26 @@
> static int rtsx_pci_runtime_suspend(struct device *device)
> 
>  	handle = pci_get_drvdata(pcidev);
>  	pcr = handle->pcr;
> -	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	cancel_delayed_work(&pcr->carddet_work);
> -	cancel_delayed_work(&pcr->rtd3_work);
> -	cancel_delayed_work(&pcr->idle_work);
> +	dev_dbg(device, "--> %s\n", __func__);
> +
> +	cancel_delayed_work_sync(&pcr->carddet_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
>  	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> 
>  	mutex_unlock(&pcr->pcr_mutex);
> 
> -	pcr->is_runtime_suspended = true;
> -
>  	return 0;
>  }
> 
>  static int rtsx_pci_runtime_resume(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device);
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> 
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
> -	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> +	dev_dbg(device, "--> %s\n", __func__);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
>  				pcr->slots[RTSX_SD_CARD].p_dev);
>  	}
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> -
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return 0;
>  }
> @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
> 
>  static const struct dev_pm_ops rtsx_pci_pm_ops = {
>  	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> -	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> rtsx_pci_runtime_resume, NULL)
> +	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> rtsx_pci_runtime_resume,
> +rtsx_pci_runtime_idle)
>  };
> 
>  static struct pci_driver rtsx_pci_driver = { diff --git a/include/linux/rtsx_pci.h
> b/include/linux/rtsx_pci.h index 4ab7bfc675f11..89b7d34e25b63 100644
> --- a/include/linux/rtsx_pci.h
> +++ b/include/linux/rtsx_pci.h
> @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
>  	unsigned int			card_exist;
> 
>  	struct delayed_work		carddet_work;
> -	struct delayed_work		idle_work;
> -	struct delayed_work		rtd3_work;
> 
>  	spinlock_t			lock;
>  	struct mutex			pcr_mutex;
> @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
>  	unsigned int			cur_clock;
>  	bool				remove_pci;
>  	bool				msi_en;
> -	bool				is_runtime_suspended;
> 
>  #define EXTRA_CAPS_SD_SDR50		(1 << 0)
>  #define EXTRA_CAPS_SD_SDR104		(1 << 1)
> --
> 2.33.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21  9:58       ` Ricky WU
@ 2022-01-21 12:39         ` Kai-Heng Feng
  2022-01-24  3:26           ` Ricky WU
  0 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-21 12:39 UTC (permalink / raw)
  To: Ricky WU
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

On Fri, Jan 21, 2022 at 5:59 PM Ricky WU <ricky_wu@realtek.com> wrote:
>
> > -----Original Message-----
> > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > Sent: Friday, January 21, 2022 2:32 PM
> > To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> > Ricky WU <ricky_wu@realtek.com>; Christophe JAILLET
> > <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> > linux-kernel@vger.kernel.org
> > Subject: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
> >
> > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> > "rtd3_work" and "idle_work" to manage it's own runtime PM state machine.
> >
> > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount correctly, all
> > the additional works can be managed by generic runtime PM helpers.
> >
> > So consolidate "idle_work" and "rtd3_work" into generic runtime idle callback
> > and runtime suspend callback, respectively.
>
>
> Original idle_work is for aspm delay time is 200 msec, because Aspm can quick in and out to save more power
> Now this patch need to wait 5 sec because set autosuspend time set to 5 sec in sdmmc,... this time need to set to 200 msec.

OK, will change it to 200ms.

>
> But it will get another question, the question is the host(sdmmc) caps has set MMC_CAP_AGGRESSIVE_PM when rtd3_en is set,
> It will make card power off when sdmmc go to suspend, 200 msec will cause card power off and on frequently
>
> Need to remove this flag in caps, and then change card power off to rtsx_pci_runtime_suspend()....

You are right, since rtsx_pci_sdmmc behaves like a virtual device of
rtsx_pci, so we should let the latter handle all the PM work.
Will drop MMC_CAP_AGGRESSIVE_PM in next iteration.

>
> What do you think?

Thanks for your testing and review.

One question though, regarding to the memstick virtual driver. The
memstick support was silently dropped by "misc: rtsx: Add support for
RTS5261", as RTSX_MS_CARD was removed from MFD cells.

Is there any memstick device in the wild? If there is, we should add
it back to the MFD cells to avoid regression.
And I guess starting from rts5261, only MMC is supported?

Kai-Heng

>
> Ricky
>
> >
> > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > Cc: Ricky WU <ricky_wu@realtek.com>
> > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > ---
> > v3:
> >  - Allow runtime PM for all devices, but only schedule runtime suspend
> >    for devices with rtd3_en flagged.
> >
> > v2:
> >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> >
> >  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
> >  include/linux/rtsx_pci.h           |   3 -
> >  2 files changed, 39 insertions(+), 82 deletions(-)
> >
> > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > b/drivers/misc/cardreader/rtsx_pcr.c
> > index 6ac509c1821c9..f919290f01192 100644
> > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> >       if (pcr->remove_pci)
> >               return;
> >
> > -     if (pcr->rtd3_en)
> > -             if (pcr->is_runtime_suspended) {
> > -                     pm_runtime_get(&(pcr->pci->dev));
> > -                     pcr->is_runtime_suspended = false;
> > -             }
> > -
> >       if (pcr->state != PDEV_STAT_RUN) {
> >               pcr->state = PDEV_STAT_RUN;
> >               if (pcr->ops->enable_auto_blink)
> >                       pcr->ops->enable_auto_blink(pcr);
> >               rtsx_pm_full_on(pcr);
> >       }
> > -
> > -     mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
> >  }
> >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> >
> > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr
> > *pcr)
> >       rtsx_comm_pm_power_saving(pcr);
> >  }
> >
> > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > -     struct delayed_work *dwork = to_delayed_work(work);
> > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
> > -
> > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > -     if (!pcr->is_runtime_suspended)
> > -             pm_runtime_put(&(pcr->pci->dev));
> > -}
> > -
> > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > -     struct delayed_work *dwork = to_delayed_work(work);
> > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
> > -
> > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > -
> > -     mutex_lock(&pcr->pcr_mutex);
> > -
> > -     pcr->state = PDEV_STAT_IDLE;
> > -
> > -     if (pcr->ops->disable_auto_blink)
> > -             pcr->ops->disable_auto_blink(pcr);
> > -     if (pcr->ops->turn_off_led)
> > -             pcr->ops->turn_off_led(pcr);
> > -
> > -     rtsx_pm_power_saving(pcr);
> > -
> > -     mutex_unlock(&pcr->pcr_mutex);
> > -
> > -     if (pcr->rtd3_en)
> > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > msecs_to_jiffies(10000));
> > -}
> > -
> >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> > {
> >       /* Set relink_time to 0 */
> > @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> >       pcr->card_inserted = 0;
> >       pcr->card_removed = 0;
> >       INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> >
> >       pcr->msi_en = msi_en;
> >       if (pcr->msi_en) {
> > @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> >       }
> >
> > -     if (pcr->rtd3_en) {
> > -             INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
> > -             pm_runtime_allow(&pcidev->dev);
> > -             pm_runtime_enable(&pcidev->dev);
> > -             pcr->is_runtime_suspended = false;
> > -     }
> > -
> >
> >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
> >       if (ret < 0)
> >               goto free_slots;
> >
> > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > +     pm_runtime_allow(&pcidev->dev);
> > +     pm_runtime_put(&pcidev->dev);
> >
> >       return 0;
> >
> > @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev
> > *pcidev)
> >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> >       struct rtsx_pcr *pcr = handle->pcr;
> >
> > -     if (pcr->rtd3_en)
> > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > -
> >       pcr->remove_pci = true;
> >
> > +     pm_runtime_get_sync(&pcidev->dev);
> > +     pm_runtime_forbid(&pcidev->dev);
> > +
> >       /* Disable interrupts at the pcr level */
> >       spin_lock_irq(&pcr->lock);
> >       rtsx_pci_writel(pcr, RTSX_BIER, 0);
> > @@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
> >       spin_unlock_irq(&pcr->lock);
> >
> >       cancel_delayed_work_sync(&pcr->carddet_work);
> > -     cancel_delayed_work_sync(&pcr->idle_work);
> > -     if (pcr->rtd3_en)
> > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> >
> >       mfd_remove_devices(&pcidev->dev);
> >
> > @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev
> > *pcidev)
> >       idr_remove(&rtsx_pci_idr, pcr->id);
> >       spin_unlock(&rtsx_pci_lock);
> >
> > -     if (pcr->rtd3_en) {
> > -             pm_runtime_disable(&pcr->pci->dev);
> > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > -     }
> > -
> >       kfree(pcr->slots);
> >       kfree(pcr);
> >       kfree(handle);
> > @@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct
> > device *dev_d)
> >       pcr = handle->pcr;
> >
> >       cancel_delayed_work(&pcr->carddet_work);
> > -     cancel_delayed_work(&pcr->idle_work);
> >
> >       mutex_lock(&pcr->pcr_mutex);
> >
> > @@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct
> > device *dev_d)
> >       if (ret)
> >               goto out;
> >
> > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > -
> >  out:
> >       mutex_unlock(&pcr->pcr_mutex);
> >       return ret;
> > @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev
> > *pcidev)
> >               pci_disable_msi(pcr->pci);
> >  }
> >
> > +static int rtsx_pci_runtime_idle(struct device *device) {
> > +     struct pci_dev *pcidev = to_pci_dev(device);
> > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > +     struct rtsx_pcr *pcr = handle->pcr;
> > +
> > +     dev_dbg(device, "--> %s\n", __func__);
> > +
> > +     mutex_lock(&pcr->pcr_mutex);
> > +
> > +     pcr->state = PDEV_STAT_IDLE;
> > +
> > +     if (pcr->ops->disable_auto_blink)
> > +             pcr->ops->disable_auto_blink(pcr);
> > +     if (pcr->ops->turn_off_led)
> > +             pcr->ops->turn_off_led(pcr);
> > +
> > +     rtsx_pm_power_saving(pcr);
> > +
> > +     mutex_unlock(&pcr->pcr_mutex);
> > +
> > +     if (pcr->rtd3_en)
> > +             pm_schedule_suspend(device, 5000);
> > +
> > +     return -EBUSY;
> > +}
> > +
> >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31 +1761,26 @@
> > static int rtsx_pci_runtime_suspend(struct device *device)
> >
> >       handle = pci_get_drvdata(pcidev);
> >       pcr = handle->pcr;
> > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> >
> > -     cancel_delayed_work(&pcr->carddet_work);
> > -     cancel_delayed_work(&pcr->rtd3_work);
> > -     cancel_delayed_work(&pcr->idle_work);
> > +     dev_dbg(device, "--> %s\n", __func__);
> > +
> > +     cancel_delayed_work_sync(&pcr->carddet_work);
> >
> >       mutex_lock(&pcr->pcr_mutex);
> >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> >
> >       mutex_unlock(&pcr->pcr_mutex);
> >
> > -     pcr->is_runtime_suspended = true;
> > -
> >       return 0;
> >  }
> >
> >  static int rtsx_pci_runtime_resume(struct device *device)  {
> >       struct pci_dev *pcidev = to_pci_dev(device);
> > -     struct pcr_handle *handle;
> > -     struct rtsx_pcr *pcr;
> > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > +     struct rtsx_pcr *pcr = handle->pcr;
> >
> > -     handle = pci_get_drvdata(pcidev);
> > -     pcr = handle->pcr;
> > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > +     dev_dbg(device, "--> %s\n", __func__);
> >
> >       mutex_lock(&pcr->pcr_mutex);
> >
> > @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device
> > *device)
> >                               pcr->slots[RTSX_SD_CARD].p_dev);
> >       }
> >
> > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > -
> >       mutex_unlock(&pcr->pcr_mutex);
> >       return 0;
> >  }
> > @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device
> > *device)
> >
> >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > rtsx_pci_runtime_resume, NULL)
> > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > rtsx_pci_runtime_resume,
> > +rtsx_pci_runtime_idle)
> >  };
> >
> >  static struct pci_driver rtsx_pci_driver = { diff --git a/include/linux/rtsx_pci.h
> > b/include/linux/rtsx_pci.h index 4ab7bfc675f11..89b7d34e25b63 100644
> > --- a/include/linux/rtsx_pci.h
> > +++ b/include/linux/rtsx_pci.h
> > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> >       unsigned int                    card_exist;
> >
> >       struct delayed_work             carddet_work;
> > -     struct delayed_work             idle_work;
> > -     struct delayed_work             rtd3_work;
> >
> >       spinlock_t                      lock;
> >       struct mutex                    pcr_mutex;
> > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> >       unsigned int                    cur_clock;
> >       bool                            remove_pci;
> >       bool                            msi_en;
> > -     bool                            is_runtime_suspended;
> >
> >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > --
> > 2.33.1
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-21 12:39         ` Kai-Heng Feng
@ 2022-01-24  3:26           ` Ricky WU
  2022-01-24  4:53             ` Kai-Heng Feng
  0 siblings, 1 reply; 35+ messages in thread
From: Ricky WU @ 2022-01-24  3:26 UTC (permalink / raw)
  To: Kai-Heng Feng
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Friday, January 21, 2022 8:39 PM
> To: Ricky WU <ricky_wu@realtek.com>
> Cc: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org;
> linux-pm@vger.kernel.org; Christophe JAILLET
> <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management
> flow
> 
> On Fri, Jan 21, 2022 at 5:59 PM Ricky WU <ricky_wu@realtek.com> wrote:
> >
> > > -----Original Message-----
> > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > Sent: Friday, January 21, 2022 2:32 PM
> > > To: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > ulf.hansson@linaro.org
> > > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng
> > > <kai.heng.feng@canonical.com>; Ricky WU <ricky_wu@realtek.com>;
> > > Christophe JAILLET <christophe.jaillet@wanadoo.fr>; Yang Li
> > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > Subject: [PATCH v3 2/4] misc: rtsx: Rework runtime power management
> > > flow
> > >
> > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> > > "rtd3_work" and "idle_work" to manage it's own runtime PM state
> machine.
> > >
> > > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
> > > correctly, all the additional works can be managed by generic runtime PM
> helpers.
> > >
> > > So consolidate "idle_work" and "rtd3_work" into generic runtime idle
> > > callback and runtime suspend callback, respectively.
> >
> >
> > Original idle_work is for aspm delay time is 200 msec, because Aspm
> > can quick in and out to save more power Now this patch need to wait 5 sec
> because set autosuspend time set to 5 sec in sdmmc,... this time need to set to
> 200 msec.
> 
> OK, will change it to 200ms.
> 
> >
> > But it will get another question, the question is the host(sdmmc) caps
> > has set MMC_CAP_AGGRESSIVE_PM when rtd3_en is set, It will make card
> > power off when sdmmc go to suspend, 200 msec will cause card power off
> > and on frequently
> >
> > Need to remove this flag in caps, and then change card power off to
> rtsx_pci_runtime_suspend()....
> 
> You are right, since rtsx_pci_sdmmc behaves like a virtual device of rtsx_pci,
> so we should let the latter handle all the PM work.
> Will drop MMC_CAP_AGGRESSIVE_PM in next iteration.
> 

We found another problem when we removed MMC_CAP_AGGRESSIVE_PM
We call rtsx_sd_power_off_card3v3 in rtsx_pci_runtime_suspend, 
we found mmc core doesn't call from CMD 0 when resume back 

> >
> > What do you think?
> 
> Thanks for your testing and review.
> 
> One question though, regarding to the memstick virtual driver. The memstick
> support was silently dropped by "misc: rtsx: Add support for RTS5261", as
> RTSX_MS_CARD was removed from MFD cells.
> 
> Is there any memstick device in the wild? If there is, we should add it back to
> the MFD cells to avoid regression.
> And I guess starting from rts5261, only MMC is supported?
> 

Yes, from rts5261 only support SD... 
But we removed MS main result is... 
1. Memstick card was disappeared about 10 year 
2. Our guest do not use combo socket, only use SD card socket so we removed MS event 

Ricky
> 
> >
> > >
> > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > ---
> > > v3:
> > >  - Allow runtime PM for all devices, but only schedule runtime suspend
> > >    for devices with rtd3_en flagged.
> > >
> > > v2:
> > >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> > >
> > >  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
> > >  include/linux/rtsx_pci.h           |   3 -
> > >  2 files changed, 39 insertions(+), 82 deletions(-)
> > >
> > > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > > b/drivers/misc/cardreader/rtsx_pcr.c
> > > index 6ac509c1821c9..f919290f01192 100644
> > > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> > >       if (pcr->remove_pci)
> > >               return;
> > >
> > > -     if (pcr->rtd3_en)
> > > -             if (pcr->is_runtime_suspended) {
> > > -                     pm_runtime_get(&(pcr->pci->dev));
> > > -                     pcr->is_runtime_suspended = false;
> > > -             }
> > > -
> > >       if (pcr->state != PDEV_STAT_RUN) {
> > >               pcr->state = PDEV_STAT_RUN;
> > >               if (pcr->ops->enable_auto_blink)
> > >                       pcr->ops->enable_auto_blink(pcr);
> > >               rtsx_pm_full_on(pcr);
> > >       }
> > > -
> > > -     mod_delayed_work(system_wq, &pcr->idle_work,
> msecs_to_jiffies(200));
> > >  }
> > >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> > >
> > > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct
> > > rtsx_pcr
> > > *pcr)
> > >       rtsx_comm_pm_power_saving(pcr);  }
> > >
> > > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> rtd3_work);
> > > -
> > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > -     if (!pcr->is_runtime_suspended)
> > > -             pm_runtime_put(&(pcr->pci->dev));
> > > -}
> > > -
> > > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> idle_work);
> > > -
> > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > -
> > > -     mutex_lock(&pcr->pcr_mutex);
> > > -
> > > -     pcr->state = PDEV_STAT_IDLE;
> > > -
> > > -     if (pcr->ops->disable_auto_blink)
> > > -             pcr->ops->disable_auto_blink(pcr);
> > > -     if (pcr->ops->turn_off_led)
> > > -             pcr->ops->turn_off_led(pcr);
> > > -
> > > -     rtsx_pm_power_saving(pcr);
> > > -
> > > -     mutex_unlock(&pcr->pcr_mutex);
> > > -
> > > -     if (pcr->rtd3_en)
> > > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > > msecs_to_jiffies(10000));
> > > -}
> > > -
> > >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8
> > > pm_state) {
> > >       /* Set relink_time to 0 */
> > > @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> > >       pcr->card_inserted = 0;
> > >       pcr->card_removed = 0;
> > >       INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> > > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> > >
> > >       pcr->msi_en = msi_en;
> > >       if (pcr->msi_en) {
> > > @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev
> *pcidev,
> > >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> > >       }
> > >
> > > -     if (pcr->rtd3_en) {
> > > -             INIT_DELAYED_WORK(&pcr->rtd3_work,
> rtsx_pci_rtd3_work);
> > > -             pm_runtime_allow(&pcidev->dev);
> > > -             pm_runtime_enable(&pcidev->dev);
> > > -             pcr->is_runtime_suspended = false;
> > > -     }
> > > -
> > >
> > >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> > >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
> > >       if (ret < 0)
> > >               goto free_slots;
> > >
> > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > +     pm_runtime_allow(&pcidev->dev);
> > > +     pm_runtime_put(&pcidev->dev);
> > >
> > >       return 0;
> > >
> > > @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev
> > > *pcidev)
> > >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > >       struct rtsx_pcr *pcr = handle->pcr;
> > >
> > > -     if (pcr->rtd3_en)
> > > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > > -
> > >       pcr->remove_pci = true;
> > >
> > > +     pm_runtime_get_sync(&pcidev->dev);
> > > +     pm_runtime_forbid(&pcidev->dev);
> > > +
> > >       /* Disable interrupts at the pcr level */
> > >       spin_lock_irq(&pcr->lock);
> > >       rtsx_pci_writel(pcr, RTSX_BIER, 0); @@ -1680,9 +1631,6 @@
> > > static void rtsx_pci_remove(struct pci_dev *pcidev)
> > >       spin_unlock_irq(&pcr->lock);
> > >
> > >       cancel_delayed_work_sync(&pcr->carddet_work);
> > > -     cancel_delayed_work_sync(&pcr->idle_work);
> > > -     if (pcr->rtd3_en)
> > > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> > >
> > >       mfd_remove_devices(&pcidev->dev);
> > >
> > > @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev
> > > *pcidev)
> > >       idr_remove(&rtsx_pci_idr, pcr->id);
> > >       spin_unlock(&rtsx_pci_lock);
> > >
> > > -     if (pcr->rtd3_en) {
> > > -             pm_runtime_disable(&pcr->pci->dev);
> > > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > > -     }
> > > -
> > >       kfree(pcr->slots);
> > >       kfree(pcr);
> > >       kfree(handle);
> > > @@ -1726,7 +1669,6 @@ static int __maybe_unused
> > > rtsx_pci_suspend(struct device *dev_d)
> > >       pcr = handle->pcr;
> > >
> > >       cancel_delayed_work(&pcr->carddet_work);
> > > -     cancel_delayed_work(&pcr->idle_work);
> > >
> > >       mutex_lock(&pcr->pcr_mutex);
> > >
> > > @@ -1760,8 +1702,6 @@ static int __maybe_unused
> > > rtsx_pci_resume(struct device *dev_d)
> > >       if (ret)
> > >               goto out;
> > >
> > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > -
> > >  out:
> > >       mutex_unlock(&pcr->pcr_mutex);
> > >       return ret;
> > > @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev
> > > *pcidev)
> > >               pci_disable_msi(pcr->pci);  }
> > >
> > > +static int rtsx_pci_runtime_idle(struct device *device) {
> > > +     struct pci_dev *pcidev = to_pci_dev(device);
> > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > +
> > > +     dev_dbg(device, "--> %s\n", __func__);
> > > +
> > > +     mutex_lock(&pcr->pcr_mutex);
> > > +
> > > +     pcr->state = PDEV_STAT_IDLE;
> > > +
> > > +     if (pcr->ops->disable_auto_blink)
> > > +             pcr->ops->disable_auto_blink(pcr);
> > > +     if (pcr->ops->turn_off_led)
> > > +             pcr->ops->turn_off_led(pcr);
> > > +
> > > +     rtsx_pm_power_saving(pcr);
> > > +
> > > +     mutex_unlock(&pcr->pcr_mutex);
> > > +
> > > +     if (pcr->rtd3_en)
> > > +             pm_schedule_suspend(device, 5000);
> > > +
> > > +     return -EBUSY;
> > > +}
> > > +
> > >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> > >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31
> > > +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device
> > > *device)
> > >
> > >       handle = pci_get_drvdata(pcidev);
> > >       pcr = handle->pcr;
> > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > >
> > > -     cancel_delayed_work(&pcr->carddet_work);
> > > -     cancel_delayed_work(&pcr->rtd3_work);
> > > -     cancel_delayed_work(&pcr->idle_work);
> > > +     dev_dbg(device, "--> %s\n", __func__);
> > > +
> > > +     cancel_delayed_work_sync(&pcr->carddet_work);
> > >
> > >       mutex_lock(&pcr->pcr_mutex);
> > >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> > >
> > >       mutex_unlock(&pcr->pcr_mutex);
> > >
> > > -     pcr->is_runtime_suspended = true;
> > > -
> > >       return 0;
> > >  }
> > >
> > >  static int rtsx_pci_runtime_resume(struct device *device)  {
> > >       struct pci_dev *pcidev = to_pci_dev(device);
> > > -     struct pcr_handle *handle;
> > > -     struct rtsx_pcr *pcr;
> > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > +     struct rtsx_pcr *pcr = handle->pcr;
> > >
> > > -     handle = pci_get_drvdata(pcidev);
> > > -     pcr = handle->pcr;
> > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > +     dev_dbg(device, "--> %s\n", __func__);
> > >
> > >       mutex_lock(&pcr->pcr_mutex);
> > >
> > > @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct
> > > device
> > > *device)
> > >                               pcr->slots[RTSX_SD_CARD].p_dev);
> > >       }
> > >
> > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > -
> > >       mutex_unlock(&pcr->pcr_mutex);
> > >       return 0;
> > >  }
> > > @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct
> > > device
> > > *device)
> > >
> > >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> > >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> > > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > rtsx_pci_runtime_resume, NULL)
> > > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > rtsx_pci_runtime_resume,
> > > +rtsx_pci_runtime_idle)
> > >  };
> > >
> > >  static struct pci_driver rtsx_pci_driver = { diff --git
> > > a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> > > 4ab7bfc675f11..89b7d34e25b63 100644
> > > --- a/include/linux/rtsx_pci.h
> > > +++ b/include/linux/rtsx_pci.h
> > > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> > >       unsigned int                    card_exist;
> > >
> > >       struct delayed_work             carddet_work;
> > > -     struct delayed_work             idle_work;
> > > -     struct delayed_work             rtd3_work;
> > >
> > >       spinlock_t                      lock;
> > >       struct mutex                    pcr_mutex;
> > > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> > >       unsigned int                    cur_clock;
> > >       bool                            remove_pci;
> > >       bool                            msi_en;
> > > -     bool                            is_runtime_suspended;
> > >
> > >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> > >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > > --
> > > 2.33.1
> >
> ------Please consider the environment before printing this e-mail.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-24  3:26           ` Ricky WU
@ 2022-01-24  4:53             ` Kai-Heng Feng
  2022-01-24  5:10               ` Ricky WU
  0 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  4:53 UTC (permalink / raw)
  To: Ricky WU
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

On Mon, Jan 24, 2022 at 11:27 AM Ricky WU <ricky_wu@realtek.com> wrote:
>
> > -----Original Message-----
> > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > Sent: Friday, January 21, 2022 8:39 PM
> > To: Ricky WU <ricky_wu@realtek.com>
> > Cc: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org;
> > linux-pm@vger.kernel.org; Christophe JAILLET
> > <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> > linux-kernel@vger.kernel.org
> > Subject: Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management
> > flow
> >
> > On Fri, Jan 21, 2022 at 5:59 PM Ricky WU <ricky_wu@realtek.com> wrote:
> > >
> > > > -----Original Message-----
> > > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > Sent: Friday, January 21, 2022 2:32 PM
> > > > To: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > > ulf.hansson@linaro.org
> > > > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng
> > > > <kai.heng.feng@canonical.com>; Ricky WU <ricky_wu@realtek.com>;
> > > > Christophe JAILLET <christophe.jaillet@wanadoo.fr>; Yang Li
> > > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > > Subject: [PATCH v3 2/4] misc: rtsx: Rework runtime power management
> > > > flow
> > > >
> > > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> > > > "rtd3_work" and "idle_work" to manage it's own runtime PM state
> > machine.
> > > >
> > > > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
> > > > correctly, all the additional works can be managed by generic runtime PM
> > helpers.
> > > >
> > > > So consolidate "idle_work" and "rtd3_work" into generic runtime idle
> > > > callback and runtime suspend callback, respectively.
> > >
> > >
> > > Original idle_work is for aspm delay time is 200 msec, because Aspm
> > > can quick in and out to save more power Now this patch need to wait 5 sec
> > because set autosuspend time set to 5 sec in sdmmc,... this time need to set to
> > 200 msec.
> >
> > OK, will change it to 200ms.
> >
> > >
> > > But it will get another question, the question is the host(sdmmc) caps
> > > has set MMC_CAP_AGGRESSIVE_PM when rtd3_en is set, It will make card
> > > power off when sdmmc go to suspend, 200 msec will cause card power off
> > > and on frequently
> > >
> > > Need to remove this flag in caps, and then change card power off to
> > rtsx_pci_runtime_suspend()....
> >
> > You are right, since rtsx_pci_sdmmc behaves like a virtual device of rtsx_pci,
> > so we should let the latter handle all the PM work.
> > Will drop MMC_CAP_AGGRESSIVE_PM in next iteration.
> >
>
> We found another problem when we removed MMC_CAP_AGGRESSIVE_PM
> We call rtsx_sd_power_off_card3v3 in rtsx_pci_runtime_suspend,
> we found mmc core doesn't call from CMD 0 when resume back

Yes, MMC_CAP_AGGRESSIVE_PM needs to be kept to power on the card on
runtime resume.
Also, I don't see the frequent powering on/off issue you describe in
previous mail. Can you please elaborate more on the issue?

>
> > >
> > > What do you think?
> >
> > Thanks for your testing and review.
> >
> > One question though, regarding to the memstick virtual driver. The memstick
> > support was silently dropped by "misc: rtsx: Add support for RTS5261", as
> > RTSX_MS_CARD was removed from MFD cells.
> >
> > Is there any memstick device in the wild? If there is, we should add it back to
> > the MFD cells to avoid regression.
> > And I guess starting from rts5261, only MMC is supported?
> >
>
> Yes, from rts5261 only support SD...
> But we removed MS main result is...
> 1. Memstick card was disappeared about 10 year

10 years isn't that long.

> 2. Our guest do not use combo socket, only use SD card socket so we removed MS event

So we should add the memstick support back for chips other than rts5261.

Kai-Heng

>
> Ricky
> >
> > >
> > > >
> > > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > ---
> > > > v3:
> > > >  - Allow runtime PM for all devices, but only schedule runtime suspend
> > > >    for devices with rtd3_en flagged.
> > > >
> > > > v2:
> > > >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> > > >
> > > >  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
> > > >  include/linux/rtsx_pci.h           |   3 -
> > > >  2 files changed, 39 insertions(+), 82 deletions(-)
> > > >
> > > > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > > > b/drivers/misc/cardreader/rtsx_pcr.c
> > > > index 6ac509c1821c9..f919290f01192 100644
> > > > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > > > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > > > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> > > >       if (pcr->remove_pci)
> > > >               return;
> > > >
> > > > -     if (pcr->rtd3_en)
> > > > -             if (pcr->is_runtime_suspended) {
> > > > -                     pm_runtime_get(&(pcr->pci->dev));
> > > > -                     pcr->is_runtime_suspended = false;
> > > > -             }
> > > > -
> > > >       if (pcr->state != PDEV_STAT_RUN) {
> > > >               pcr->state = PDEV_STAT_RUN;
> > > >               if (pcr->ops->enable_auto_blink)
> > > >                       pcr->ops->enable_auto_blink(pcr);
> > > >               rtsx_pm_full_on(pcr);
> > > >       }
> > > > -
> > > > -     mod_delayed_work(system_wq, &pcr->idle_work,
> > msecs_to_jiffies(200));
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> > > >
> > > > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct
> > > > rtsx_pcr
> > > > *pcr)
> > > >       rtsx_comm_pm_power_saving(pcr);  }
> > > >
> > > > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > rtd3_work);
> > > > -
> > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > -     if (!pcr->is_runtime_suspended)
> > > > -             pm_runtime_put(&(pcr->pci->dev));
> > > > -}
> > > > -
> > > > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > idle_work);
> > > > -
> > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > -
> > > > -     mutex_lock(&pcr->pcr_mutex);
> > > > -
> > > > -     pcr->state = PDEV_STAT_IDLE;
> > > > -
> > > > -     if (pcr->ops->disable_auto_blink)
> > > > -             pcr->ops->disable_auto_blink(pcr);
> > > > -     if (pcr->ops->turn_off_led)
> > > > -             pcr->ops->turn_off_led(pcr);
> > > > -
> > > > -     rtsx_pm_power_saving(pcr);
> > > > -
> > > > -     mutex_unlock(&pcr->pcr_mutex);
> > > > -
> > > > -     if (pcr->rtd3_en)
> > > > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > > > msecs_to_jiffies(10000));
> > > > -}
> > > > -
> > > >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8
> > > > pm_state) {
> > > >       /* Set relink_time to 0 */
> > > > @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
> > > >       pcr->card_inserted = 0;
> > > >       pcr->card_removed = 0;
> > > >       INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> > > > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> > > >
> > > >       pcr->msi_en = msi_en;
> > > >       if (pcr->msi_en) {
> > > > @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev
> > *pcidev,
> > > >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> > > >       }
> > > >
> > > > -     if (pcr->rtd3_en) {
> > > > -             INIT_DELAYED_WORK(&pcr->rtd3_work,
> > rtsx_pci_rtd3_work);
> > > > -             pm_runtime_allow(&pcidev->dev);
> > > > -             pm_runtime_enable(&pcidev->dev);
> > > > -             pcr->is_runtime_suspended = false;
> > > > -     }
> > > > -
> > > >
> > > >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> > > >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
> > > >       if (ret < 0)
> > > >               goto free_slots;
> > > >
> > > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > > +     pm_runtime_allow(&pcidev->dev);
> > > > +     pm_runtime_put(&pcidev->dev);
> > > >
> > > >       return 0;
> > > >
> > > > @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev
> > > > *pcidev)
> > > >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > >       struct rtsx_pcr *pcr = handle->pcr;
> > > >
> > > > -     if (pcr->rtd3_en)
> > > > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > > > -
> > > >       pcr->remove_pci = true;
> > > >
> > > > +     pm_runtime_get_sync(&pcidev->dev);
> > > > +     pm_runtime_forbid(&pcidev->dev);
> > > > +
> > > >       /* Disable interrupts at the pcr level */
> > > >       spin_lock_irq(&pcr->lock);
> > > >       rtsx_pci_writel(pcr, RTSX_BIER, 0); @@ -1680,9 +1631,6 @@
> > > > static void rtsx_pci_remove(struct pci_dev *pcidev)
> > > >       spin_unlock_irq(&pcr->lock);
> > > >
> > > >       cancel_delayed_work_sync(&pcr->carddet_work);
> > > > -     cancel_delayed_work_sync(&pcr->idle_work);
> > > > -     if (pcr->rtd3_en)
> > > > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> > > >
> > > >       mfd_remove_devices(&pcidev->dev);
> > > >
> > > > @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev
> > > > *pcidev)
> > > >       idr_remove(&rtsx_pci_idr, pcr->id);
> > > >       spin_unlock(&rtsx_pci_lock);
> > > >
> > > > -     if (pcr->rtd3_en) {
> > > > -             pm_runtime_disable(&pcr->pci->dev);
> > > > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > > > -     }
> > > > -
> > > >       kfree(pcr->slots);
> > > >       kfree(pcr);
> > > >       kfree(handle);
> > > > @@ -1726,7 +1669,6 @@ static int __maybe_unused
> > > > rtsx_pci_suspend(struct device *dev_d)
> > > >       pcr = handle->pcr;
> > > >
> > > >       cancel_delayed_work(&pcr->carddet_work);
> > > > -     cancel_delayed_work(&pcr->idle_work);
> > > >
> > > >       mutex_lock(&pcr->pcr_mutex);
> > > >
> > > > @@ -1760,8 +1702,6 @@ static int __maybe_unused
> > > > rtsx_pci_resume(struct device *dev_d)
> > > >       if (ret)
> > > >               goto out;
> > > >
> > > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > > -
> > > >  out:
> > > >       mutex_unlock(&pcr->pcr_mutex);
> > > >       return ret;
> > > > @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev
> > > > *pcidev)
> > > >               pci_disable_msi(pcr->pci);  }
> > > >
> > > > +static int rtsx_pci_runtime_idle(struct device *device) {
> > > > +     struct pci_dev *pcidev = to_pci_dev(device);
> > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > > +
> > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > +
> > > > +     mutex_lock(&pcr->pcr_mutex);
> > > > +
> > > > +     pcr->state = PDEV_STAT_IDLE;
> > > > +
> > > > +     if (pcr->ops->disable_auto_blink)
> > > > +             pcr->ops->disable_auto_blink(pcr);
> > > > +     if (pcr->ops->turn_off_led)
> > > > +             pcr->ops->turn_off_led(pcr);
> > > > +
> > > > +     rtsx_pm_power_saving(pcr);
> > > > +
> > > > +     mutex_unlock(&pcr->pcr_mutex);
> > > > +
> > > > +     if (pcr->rtd3_en)
> > > > +             pm_schedule_suspend(device, 5000);
> > > > +
> > > > +     return -EBUSY;
> > > > +}
> > > > +
> > > >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> > > >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31
> > > > +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device
> > > > *device)
> > > >
> > > >       handle = pci_get_drvdata(pcidev);
> > > >       pcr = handle->pcr;
> > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > >
> > > > -     cancel_delayed_work(&pcr->carddet_work);
> > > > -     cancel_delayed_work(&pcr->rtd3_work);
> > > > -     cancel_delayed_work(&pcr->idle_work);
> > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > +
> > > > +     cancel_delayed_work_sync(&pcr->carddet_work);
> > > >
> > > >       mutex_lock(&pcr->pcr_mutex);
> > > >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> > > >
> > > >       mutex_unlock(&pcr->pcr_mutex);
> > > >
> > > > -     pcr->is_runtime_suspended = true;
> > > > -
> > > >       return 0;
> > > >  }
> > > >
> > > >  static int rtsx_pci_runtime_resume(struct device *device)  {
> > > >       struct pci_dev *pcidev = to_pci_dev(device);
> > > > -     struct pcr_handle *handle;
> > > > -     struct rtsx_pcr *pcr;
> > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > >
> > > > -     handle = pci_get_drvdata(pcidev);
> > > > -     pcr = handle->pcr;
> > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > >
> > > >       mutex_lock(&pcr->pcr_mutex);
> > > >
> > > > @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct
> > > > device
> > > > *device)
> > > >                               pcr->slots[RTSX_SD_CARD].p_dev);
> > > >       }
> > > >
> > > > -     schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> > > > -
> > > >       mutex_unlock(&pcr->pcr_mutex);
> > > >       return 0;
> > > >  }
> > > > @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct
> > > > device
> > > > *device)
> > > >
> > > >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> > > >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> > > > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > rtsx_pci_runtime_resume, NULL)
> > > > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > rtsx_pci_runtime_resume,
> > > > +rtsx_pci_runtime_idle)
> > > >  };
> > > >
> > > >  static struct pci_driver rtsx_pci_driver = { diff --git
> > > > a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> > > > 4ab7bfc675f11..89b7d34e25b63 100644
> > > > --- a/include/linux/rtsx_pci.h
> > > > +++ b/include/linux/rtsx_pci.h
> > > > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> > > >       unsigned int                    card_exist;
> > > >
> > > >       struct delayed_work             carddet_work;
> > > > -     struct delayed_work             idle_work;
> > > > -     struct delayed_work             rtd3_work;
> > > >
> > > >       spinlock_t                      lock;
> > > >       struct mutex                    pcr_mutex;
> > > > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> > > >       unsigned int                    cur_clock;
> > > >       bool                            remove_pci;
> > > >       bool                            msi_en;
> > > > -     bool                            is_runtime_suspended;
> > > >
> > > >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> > > >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > > > --
> > > > 2.33.1
> > >
> > ------Please consider the environment before printing this e-mail.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-24  4:53             ` Kai-Heng Feng
@ 2022-01-24  5:10               ` Ricky WU
  2022-01-24  5:26                 ` Kai-Heng Feng
  0 siblings, 1 reply; 35+ messages in thread
From: Ricky WU @ 2022-01-24  5:10 UTC (permalink / raw)
  To: Kai-Heng Feng
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Monday, January 24, 2022 12:54 PM
> To: Ricky WU <ricky_wu@realtek.com>
> Cc: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org;
> linux-pm@vger.kernel.org; Christophe JAILLET
> <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management
> flow
> 
> On Mon, Jan 24, 2022 at 11:27 AM Ricky WU <ricky_wu@realtek.com> wrote:
> >
> > > -----Original Message-----
> > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > Sent: Friday, January 21, 2022 8:39 PM
> > > To: Ricky WU <ricky_wu@realtek.com>
> > > Cc: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > ulf.hansson@linaro.org; linux-pm@vger.kernel.org; Christophe JAILLET
> > > <christophe.jaillet@wanadoo.fr>; Yang Li
> > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > Subject: Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power
> > > management flow
> > >
> > > On Fri, Jan 21, 2022 at 5:59 PM Ricky WU <ricky_wu@realtek.com> wrote:
> > > >
> > > > > -----Original Message-----
> > > > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > > Sent: Friday, January 21, 2022 2:32 PM
> > > > > To: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > > > ulf.hansson@linaro.org
> > > > > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng
> > > > > <kai.heng.feng@canonical.com>; Ricky WU <ricky_wu@realtek.com>;
> > > > > Christophe JAILLET <christophe.jaillet@wanadoo.fr>; Yang Li
> > > > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > > > Subject: [PATCH v3 2/4] misc: rtsx: Rework runtime power
> > > > > management flow
> > > > >
> > > > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > > > uses "rtd3_work" and "idle_work" to manage it's own runtime PM
> > > > > state
> > > machine.
> > > > >
> > > > > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
> > > > > correctly, all the additional works can be managed by generic
> > > > > runtime PM
> > > helpers.
> > > > >
> > > > > So consolidate "idle_work" and "rtd3_work" into generic runtime
> > > > > idle callback and runtime suspend callback, respectively.
> > > >
> > > >
> > > > Original idle_work is for aspm delay time is 200 msec, because
> > > > Aspm can quick in and out to save more power Now this patch need
> > > > to wait 5 sec
> > > because set autosuspend time set to 5 sec in sdmmc,... this time
> > > need to set to
> > > 200 msec.
> > >
> > > OK, will change it to 200ms.
> > >
> > > >
> > > > But it will get another question, the question is the host(sdmmc)
> > > > caps has set MMC_CAP_AGGRESSIVE_PM when rtd3_en is set, It will
> > > > make card power off when sdmmc go to suspend, 200 msec will cause
> > > > card power off and on frequently
> > > >
> > > > Need to remove this flag in caps, and then change card power off
> > > > to
> > > rtsx_pci_runtime_suspend()....
> > >
> > > You are right, since rtsx_pci_sdmmc behaves like a virtual device of
> > > rtsx_pci, so we should let the latter handle all the PM work.
> > > Will drop MMC_CAP_AGGRESSIVE_PM in next iteration.
> > >
> >
> > We found another problem when we removed MMC_CAP_AGGRESSIVE_PM
> We call
> > rtsx_sd_power_off_card3v3 in rtsx_pci_runtime_suspend, we found mmc
> > core doesn't call from CMD 0 when resume back
> 
> Yes, MMC_CAP_AGGRESSIVE_PM needs to be kept to power on the card on
> runtime resume.
> Also, I don't see the frequent powering on/off issue you describe in previous
> mail. Can you please elaborate more on the issue?
> 

We think keep MMC_CAP_AGGRESSIVE_PM exist Is better for now 
Also keep the rtsx_pci_sdmmc autsuspend 5 Sec is well
After 5 Sec idle and then power off the card we think this behavior is not a problem


> >
> > > >
> > > > What do you think?
> > >
> > > Thanks for your testing and review.
> > >
> > > One question though, regarding to the memstick virtual driver. The
> > > memstick support was silently dropped by "misc: rtsx: Add support
> > > for RTS5261", as RTSX_MS_CARD was removed from MFD cells.
> > >
> > > Is there any memstick device in the wild? If there is, we should add
> > > it back to the MFD cells to avoid regression.
> > > And I guess starting from rts5261, only MMC is supported?
> > >
> >
> > Yes, from rts5261 only support SD...
> > But we removed MS main result is...
> > 1. Memstick card was disappeared about 10 year
> 
> 10 years isn't that long.
> 
> > 2. Our guest do not use combo socket, only use SD card socket so we
> > removed MS event
> 
> So we should add the memstick support back for chips other than rts5261.
> 

We didn’t have guest to use combo socket (SD and MS),
so we think support MS is unnecessary

> Kai-Heng
> 
> >
> > Ricky
> > >
> > > >
> > > > >
> > > > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > > ---
> > > > > v3:
> > > > >  - Allow runtime PM for all devices, but only schedule runtime
> suspend
> > > > >    for devices with rtd3_en flagged.
> > > > >
> > > > > v2:
> > > > >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> > > > >
> > > > >  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
> > > > >  include/linux/rtsx_pci.h           |   3 -
> > > > >  2 files changed, 39 insertions(+), 82 deletions(-)
> > > > >
> > > > > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > > > > b/drivers/misc/cardreader/rtsx_pcr.c
> > > > > index 6ac509c1821c9..f919290f01192 100644
> > > > > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > > > > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > > > > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> > > > >       if (pcr->remove_pci)
> > > > >               return;
> > > > >
> > > > > -     if (pcr->rtd3_en)
> > > > > -             if (pcr->is_runtime_suspended) {
> > > > > -                     pm_runtime_get(&(pcr->pci->dev));
> > > > > -                     pcr->is_runtime_suspended = false;
> > > > > -             }
> > > > > -
> > > > >       if (pcr->state != PDEV_STAT_RUN) {
> > > > >               pcr->state = PDEV_STAT_RUN;
> > > > >               if (pcr->ops->enable_auto_blink)
> > > > >                       pcr->ops->enable_auto_blink(pcr);
> > > > >               rtsx_pm_full_on(pcr);
> > > > >       }
> > > > > -
> > > > > -     mod_delayed_work(system_wq, &pcr->idle_work,
> > > msecs_to_jiffies(200));
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> > > > >
> > > > > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct
> > > > > rtsx_pcr
> > > > > *pcr)
> > > > >       rtsx_comm_pm_power_saving(pcr);  }
> > > > >
> > > > > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > > rtd3_work);
> > > > > -
> > > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > > -     if (!pcr->is_runtime_suspended)
> > > > > -             pm_runtime_put(&(pcr->pci->dev));
> > > > > -}
> > > > > -
> > > > > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > > idle_work);
> > > > > -
> > > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > > -
> > > > > -     mutex_lock(&pcr->pcr_mutex);
> > > > > -
> > > > > -     pcr->state = PDEV_STAT_IDLE;
> > > > > -
> > > > > -     if (pcr->ops->disable_auto_blink)
> > > > > -             pcr->ops->disable_auto_blink(pcr);
> > > > > -     if (pcr->ops->turn_off_led)
> > > > > -             pcr->ops->turn_off_led(pcr);
> > > > > -
> > > > > -     rtsx_pm_power_saving(pcr);
> > > > > -
> > > > > -     mutex_unlock(&pcr->pcr_mutex);
> > > > > -
> > > > > -     if (pcr->rtd3_en)
> > > > > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > > > > msecs_to_jiffies(10000));
> > > > > -}
> > > > > -
> > > > >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8
> > > > > pm_state) {
> > > > >       /* Set relink_time to 0 */ @@ -1598,7 +1556,6 @@ static
> > > > > int rtsx_pci_probe(struct pci_dev *pcidev,
> > > > >       pcr->card_inserted = 0;
> > > > >       pcr->card_removed = 0;
> > > > >       INIT_DELAYED_WORK(&pcr->carddet_work,
> rtsx_pci_card_detect);
> > > > > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> > > > >
> > > > >       pcr->msi_en = msi_en;
> > > > >       if (pcr->msi_en) {
> > > > > @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev
> > > *pcidev,
> > > > >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> > > > >       }
> > > > >
> > > > > -     if (pcr->rtd3_en) {
> > > > > -             INIT_DELAYED_WORK(&pcr->rtd3_work,
> > > rtsx_pci_rtd3_work);
> > > > > -             pm_runtime_allow(&pcidev->dev);
> > > > > -             pm_runtime_enable(&pcidev->dev);
> > > > > -             pcr->is_runtime_suspended = false;
> > > > > -     }
> > > > > -
> > > > >
> > > > >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> > > > >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0,
> NULL);
> > > > >       if (ret < 0)
> > > > >               goto free_slots;
> > > > >
> > > > > -     schedule_delayed_work(&pcr->idle_work,
> msecs_to_jiffies(200));
> > > > > +     pm_runtime_allow(&pcidev->dev);
> > > > > +     pm_runtime_put(&pcidev->dev);
> > > > >
> > > > >       return 0;
> > > > >
> > > > > @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct
> > > > > pci_dev
> > > > > *pcidev)
> > > > >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > >       struct rtsx_pcr *pcr = handle->pcr;
> > > > >
> > > > > -     if (pcr->rtd3_en)
> > > > > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > > > > -
> > > > >       pcr->remove_pci = true;
> > > > >
> > > > > +     pm_runtime_get_sync(&pcidev->dev);
> > > > > +     pm_runtime_forbid(&pcidev->dev);
> > > > > +
> > > > >       /* Disable interrupts at the pcr level */
> > > > >       spin_lock_irq(&pcr->lock);
> > > > >       rtsx_pci_writel(pcr, RTSX_BIER, 0); @@ -1680,9 +1631,6 @@
> > > > > static void rtsx_pci_remove(struct pci_dev *pcidev)
> > > > >       spin_unlock_irq(&pcr->lock);
> > > > >
> > > > >       cancel_delayed_work_sync(&pcr->carddet_work);
> > > > > -     cancel_delayed_work_sync(&pcr->idle_work);
> > > > > -     if (pcr->rtd3_en)
> > > > > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> > > > >
> > > > >       mfd_remove_devices(&pcidev->dev);
> > > > >
> > > > > @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct
> > > > > pci_dev
> > > > > *pcidev)
> > > > >       idr_remove(&rtsx_pci_idr, pcr->id);
> > > > >       spin_unlock(&rtsx_pci_lock);
> > > > >
> > > > > -     if (pcr->rtd3_en) {
> > > > > -             pm_runtime_disable(&pcr->pci->dev);
> > > > > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > > > > -     }
> > > > > -
> > > > >       kfree(pcr->slots);
> > > > >       kfree(pcr);
> > > > >       kfree(handle);
> > > > > @@ -1726,7 +1669,6 @@ static int __maybe_unused
> > > > > rtsx_pci_suspend(struct device *dev_d)
> > > > >       pcr = handle->pcr;
> > > > >
> > > > >       cancel_delayed_work(&pcr->carddet_work);
> > > > > -     cancel_delayed_work(&pcr->idle_work);
> > > > >
> > > > >       mutex_lock(&pcr->pcr_mutex);
> > > > >
> > > > > @@ -1760,8 +1702,6 @@ static int __maybe_unused
> > > > > rtsx_pci_resume(struct device *dev_d)
> > > > >       if (ret)
> > > > >               goto out;
> > > > >
> > > > > -     schedule_delayed_work(&pcr->idle_work,
> msecs_to_jiffies(200));
> > > > > -
> > > > >  out:
> > > > >       mutex_unlock(&pcr->pcr_mutex);
> > > > >       return ret;
> > > > > @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct
> > > > > pci_dev
> > > > > *pcidev)
> > > > >               pci_disable_msi(pcr->pci);  }
> > > > >
> > > > > +static int rtsx_pci_runtime_idle(struct device *device) {
> > > > > +     struct pci_dev *pcidev = to_pci_dev(device);
> > > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > > > +
> > > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > > +
> > > > > +     mutex_lock(&pcr->pcr_mutex);
> > > > > +
> > > > > +     pcr->state = PDEV_STAT_IDLE;
> > > > > +
> > > > > +     if (pcr->ops->disable_auto_blink)
> > > > > +             pcr->ops->disable_auto_blink(pcr);
> > > > > +     if (pcr->ops->turn_off_led)
> > > > > +             pcr->ops->turn_off_led(pcr);
> > > > > +
> > > > > +     rtsx_pm_power_saving(pcr);
> > > > > +
> > > > > +     mutex_unlock(&pcr->pcr_mutex);
> > > > > +
> > > > > +     if (pcr->rtd3_en)
> > > > > +             pm_schedule_suspend(device, 5000);
> > > > > +
> > > > > +     return -EBUSY;
> > > > > +}
> > > > > +
> > > > >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> > > > >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31
> > > > > +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device
> > > > > *device)
> > > > >
> > > > >       handle = pci_get_drvdata(pcidev);
> > > > >       pcr = handle->pcr;
> > > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > > >
> > > > > -     cancel_delayed_work(&pcr->carddet_work);
> > > > > -     cancel_delayed_work(&pcr->rtd3_work);
> > > > > -     cancel_delayed_work(&pcr->idle_work);
> > > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > > +
> > > > > +     cancel_delayed_work_sync(&pcr->carddet_work);
> > > > >
> > > > >       mutex_lock(&pcr->pcr_mutex);
> > > > >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> > > > >
> > > > >       mutex_unlock(&pcr->pcr_mutex);
> > > > >
> > > > > -     pcr->is_runtime_suspended = true;
> > > > > -
> > > > >       return 0;
> > > > >  }
> > > > >
> > > > >  static int rtsx_pci_runtime_resume(struct device *device)  {
> > > > >       struct pci_dev *pcidev = to_pci_dev(device);
> > > > > -     struct pcr_handle *handle;
> > > > > -     struct rtsx_pcr *pcr;
> > > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > > >
> > > > > -     handle = pci_get_drvdata(pcidev);
> > > > > -     pcr = handle->pcr;
> > > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > >
> > > > >       mutex_lock(&pcr->pcr_mutex);
> > > > >
> > > > > @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct
> > > > > device
> > > > > *device)
> > > > >
> pcr->slots[RTSX_SD_CARD].p_dev);
> > > > >       }
> > > > >
> > > > > -     schedule_delayed_work(&pcr->idle_work,
> msecs_to_jiffies(200));
> > > > > -
> > > > >       mutex_unlock(&pcr->pcr_mutex);
> > > > >       return 0;
> > > > >  }
> > > > > @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct
> > > > > device
> > > > > *device)
> > > > >
> > > > >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> > > > >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend,
> rtsx_pci_resume)
> > > > > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > > rtsx_pci_runtime_resume, NULL)
> > > > > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > > rtsx_pci_runtime_resume,
> > > > > +rtsx_pci_runtime_idle)
> > > > >  };
> > > > >
> > > > >  static struct pci_driver rtsx_pci_driver = { diff --git
> > > > > a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> > > > > 4ab7bfc675f11..89b7d34e25b63 100644
> > > > > --- a/include/linux/rtsx_pci.h
> > > > > +++ b/include/linux/rtsx_pci.h
> > > > > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> > > > >       unsigned int                    card_exist;
> > > > >
> > > > >       struct delayed_work             carddet_work;
> > > > > -     struct delayed_work             idle_work;
> > > > > -     struct delayed_work             rtd3_work;
> > > > >
> > > > >       spinlock_t                      lock;
> > > > >       struct mutex                    pcr_mutex;
> > > > > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> > > > >       unsigned int                    cur_clock;
> > > > >       bool                            remove_pci;
> > > > >       bool                            msi_en;
> > > > > -     bool                            is_runtime_suspended;
> > > > >
> > > > >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> > > > >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > > > > --
> > > > > 2.33.1
> > > >
> > > ------Please consider the environment before printing this e-mail.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-24  5:10               ` Ricky WU
@ 2022-01-24  5:26                 ` Kai-Heng Feng
  0 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  5:26 UTC (permalink / raw)
  To: Ricky WU
  Cc: arnd, gregkh, ulf.hansson, linux-pm, Christophe JAILLET, Yang Li,
	linux-kernel

On Mon, Jan 24, 2022 at 1:11 PM Ricky WU <ricky_wu@realtek.com> wrote:
>
> > -----Original Message-----
> > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > Sent: Monday, January 24, 2022 12:54 PM
> > To: Ricky WU <ricky_wu@realtek.com>
> > Cc: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org;
> > linux-pm@vger.kernel.org; Christophe JAILLET
> > <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> > linux-kernel@vger.kernel.org
> > Subject: Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power management
> > flow
> >
> > On Mon, Jan 24, 2022 at 11:27 AM Ricky WU <ricky_wu@realtek.com> wrote:
> > >
> > > > -----Original Message-----
> > > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > Sent: Friday, January 21, 2022 8:39 PM
> > > > To: Ricky WU <ricky_wu@realtek.com>
> > > > Cc: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > > ulf.hansson@linaro.org; linux-pm@vger.kernel.org; Christophe JAILLET
> > > > <christophe.jaillet@wanadoo.fr>; Yang Li
> > > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > > Subject: Re: [PATCH v3 2/4] misc: rtsx: Rework runtime power
> > > > management flow
> > > >
> > > > On Fri, Jan 21, 2022 at 5:59 PM Ricky WU <ricky_wu@realtek.com> wrote:
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > > > Sent: Friday, January 21, 2022 2:32 PM
> > > > > > To: arnd@arndb.de; gregkh@linuxfoundation.org;
> > > > > > ulf.hansson@linaro.org
> > > > > > Cc: linux-pm@vger.kernel.org; Kai-Heng Feng
> > > > > > <kai.heng.feng@canonical.com>; Ricky WU <ricky_wu@realtek.com>;
> > > > > > Christophe JAILLET <christophe.jaillet@wanadoo.fr>; Yang Li
> > > > > > <yang.lee@linux.alibaba.com>; linux-kernel@vger.kernel.org
> > > > > > Subject: [PATCH v3 2/4] misc: rtsx: Rework runtime power
> > > > > > management flow
> > > > > >
> > > > > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > > > > uses "rtd3_work" and "idle_work" to manage it's own runtime PM
> > > > > > state
> > > > machine.
> > > > > >
> > > > > > When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
> > > > > > correctly, all the additional works can be managed by generic
> > > > > > runtime PM
> > > > helpers.
> > > > > >
> > > > > > So consolidate "idle_work" and "rtd3_work" into generic runtime
> > > > > > idle callback and runtime suspend callback, respectively.
> > > > >
> > > > >
> > > > > Original idle_work is for aspm delay time is 200 msec, because
> > > > > Aspm can quick in and out to save more power Now this patch need
> > > > > to wait 5 sec
> > > > because set autosuspend time set to 5 sec in sdmmc,... this time
> > > > need to set to
> > > > 200 msec.
> > > >
> > > > OK, will change it to 200ms.
> > > >
> > > > >
> > > > > But it will get another question, the question is the host(sdmmc)
> > > > > caps has set MMC_CAP_AGGRESSIVE_PM when rtd3_en is set, It will
> > > > > make card power off when sdmmc go to suspend, 200 msec will cause
> > > > > card power off and on frequently
> > > > >
> > > > > Need to remove this flag in caps, and then change card power off
> > > > > to
> > > > rtsx_pci_runtime_suspend()....
> > > >
> > > > You are right, since rtsx_pci_sdmmc behaves like a virtual device of
> > > > rtsx_pci, so we should let the latter handle all the PM work.
> > > > Will drop MMC_CAP_AGGRESSIVE_PM in next iteration.
> > > >
> > >
> > > We found another problem when we removed MMC_CAP_AGGRESSIVE_PM
> > We call
> > > rtsx_sd_power_off_card3v3 in rtsx_pci_runtime_suspend, we found mmc
> > > core doesn't call from CMD 0 when resume back
> >
> > Yes, MMC_CAP_AGGRESSIVE_PM needs to be kept to power on the card on
> > runtime resume.
> > Also, I don't see the frequent powering on/off issue you describe in previous
> > mail. Can you please elaborate more on the issue?
> >
>
> We think keep MMC_CAP_AGGRESSIVE_PM exist Is better for now
> Also keep the rtsx_pci_sdmmc autsuspend 5 Sec is well
> After 5 Sec idle and then power off the card we think this behavior is not a problem

Thanks, I'll send next version to mailing list.

>
>
> > >
> > > > >
> > > > > What do you think?
> > > >
> > > > Thanks for your testing and review.
> > > >
> > > > One question though, regarding to the memstick virtual driver. The
> > > > memstick support was silently dropped by "misc: rtsx: Add support
> > > > for RTS5261", as RTSX_MS_CARD was removed from MFD cells.
> > > >
> > > > Is there any memstick device in the wild? If there is, we should add
> > > > it back to the MFD cells to avoid regression.
> > > > And I guess starting from rts5261, only MMC is supported?
> > > >
> > >
> > > Yes, from rts5261 only support SD...
> > > But we removed MS main result is...
> > > 1. Memstick card was disappeared about 10 year
> >
> > 10 years isn't that long.
> >
> > > 2. Our guest do not use combo socket, only use SD card socket so we
> > > removed MS event
> >
> > So we should add the memstick support back for chips other than rts5261.
> >
>
> We didn’t have guest to use combo socket (SD and MS),
> so we think support MS is unnecessary

For newer hardware, yes the support is redundant.

But what about old hardwares? Was there any memstick hardware shipped?
Maybe there are still some users?

Kai-Heng

>
> > Kai-Heng
> >
> > >
> > > Ricky
> > > >
> > > > >
> > > > > >
> > > > > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > > > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > > > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> > > > > > ---
> > > > > > v3:
> > > > > >  - Allow runtime PM for all devices, but only schedule runtime
> > suspend
> > > > > >    for devices with rtd3_en flagged.
> > > > > >
> > > > > > v2:
> > > > > >  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> > > > > >
> > > > > >  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
> > > > > >  include/linux/rtsx_pci.h           |   3 -
> > > > > >  2 files changed, 39 insertions(+), 82 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> > > > > > b/drivers/misc/cardreader/rtsx_pcr.c
> > > > > > index 6ac509c1821c9..f919290f01192 100644
> > > > > > --- a/drivers/misc/cardreader/rtsx_pcr.c
> > > > > > +++ b/drivers/misc/cardreader/rtsx_pcr.c
> > > > > > @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
> > > > > >       if (pcr->remove_pci)
> > > > > >               return;
> > > > > >
> > > > > > -     if (pcr->rtd3_en)
> > > > > > -             if (pcr->is_runtime_suspended) {
> > > > > > -                     pm_runtime_get(&(pcr->pci->dev));
> > > > > > -                     pcr->is_runtime_suspended = false;
> > > > > > -             }
> > > > > > -
> > > > > >       if (pcr->state != PDEV_STAT_RUN) {
> > > > > >               pcr->state = PDEV_STAT_RUN;
> > > > > >               if (pcr->ops->enable_auto_blink)
> > > > > >                       pcr->ops->enable_auto_blink(pcr);
> > > > > >               rtsx_pm_full_on(pcr);
> > > > > >       }
> > > > > > -
> > > > > > -     mod_delayed_work(system_wq, &pcr->idle_work,
> > > > msecs_to_jiffies(200));
> > > > > >  }
> > > > > >  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> > > > > >
> > > > > > @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct
> > > > > > rtsx_pcr
> > > > > > *pcr)
> > > > > >       rtsx_comm_pm_power_saving(pcr);  }
> > > > > >
> > > > > > -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> > > > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > > > rtd3_work);
> > > > > > -
> > > > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > > > -     if (!pcr->is_runtime_suspended)
> > > > > > -             pm_runtime_put(&(pcr->pci->dev));
> > > > > > -}
> > > > > > -
> > > > > > -static void rtsx_pci_idle_work(struct work_struct *work) -{
> > > > > > -     struct delayed_work *dwork = to_delayed_work(work);
> > > > > > -     struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr,
> > > > idle_work);
> > > > > > -
> > > > > > -     pcr_dbg(pcr, "--> %s\n", __func__);
> > > > > > -
> > > > > > -     mutex_lock(&pcr->pcr_mutex);
> > > > > > -
> > > > > > -     pcr->state = PDEV_STAT_IDLE;
> > > > > > -
> > > > > > -     if (pcr->ops->disable_auto_blink)
> > > > > > -             pcr->ops->disable_auto_blink(pcr);
> > > > > > -     if (pcr->ops->turn_off_led)
> > > > > > -             pcr->ops->turn_off_led(pcr);
> > > > > > -
> > > > > > -     rtsx_pm_power_saving(pcr);
> > > > > > -
> > > > > > -     mutex_unlock(&pcr->pcr_mutex);
> > > > > > -
> > > > > > -     if (pcr->rtd3_en)
> > > > > > -             mod_delayed_work(system_wq, &pcr->rtd3_work,
> > > > > > msecs_to_jiffies(10000));
> > > > > > -}
> > > > > > -
> > > > > >  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8
> > > > > > pm_state) {
> > > > > >       /* Set relink_time to 0 */ @@ -1598,7 +1556,6 @@ static
> > > > > > int rtsx_pci_probe(struct pci_dev *pcidev,
> > > > > >       pcr->card_inserted = 0;
> > > > > >       pcr->card_removed = 0;
> > > > > >       INIT_DELAYED_WORK(&pcr->carddet_work,
> > rtsx_pci_card_detect);
> > > > > > -     INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> > > > > >
> > > > > >       pcr->msi_en = msi_en;
> > > > > >       if (pcr->msi_en) {
> > > > > > @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev
> > > > *pcidev,
> > > > > >               rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
> > > > > >       }
> > > > > >
> > > > > > -     if (pcr->rtd3_en) {
> > > > > > -             INIT_DELAYED_WORK(&pcr->rtd3_work,
> > > > rtsx_pci_rtd3_work);
> > > > > > -             pm_runtime_allow(&pcidev->dev);
> > > > > > -             pm_runtime_enable(&pcidev->dev);
> > > > > > -             pcr->is_runtime_suspended = false;
> > > > > > -     }
> > > > > > -
> > > > > >
> > > > > >       ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
> > > > > >                       ARRAY_SIZE(rtsx_pcr_cells), NULL, 0,
> > NULL);
> > > > > >       if (ret < 0)
> > > > > >               goto free_slots;
> > > > > >
> > > > > > -     schedule_delayed_work(&pcr->idle_work,
> > msecs_to_jiffies(200));
> > > > > > +     pm_runtime_allow(&pcidev->dev);
> > > > > > +     pm_runtime_put(&pcidev->dev);
> > > > > >
> > > > > >       return 0;
> > > > > >
> > > > > > @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct
> > > > > > pci_dev
> > > > > > *pcidev)
> > > > > >       struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > > >       struct rtsx_pcr *pcr = handle->pcr;
> > > > > >
> > > > > > -     if (pcr->rtd3_en)
> > > > > > -             pm_runtime_get_noresume(&pcr->pci->dev);
> > > > > > -
> > > > > >       pcr->remove_pci = true;
> > > > > >
> > > > > > +     pm_runtime_get_sync(&pcidev->dev);
> > > > > > +     pm_runtime_forbid(&pcidev->dev);
> > > > > > +
> > > > > >       /* Disable interrupts at the pcr level */
> > > > > >       spin_lock_irq(&pcr->lock);
> > > > > >       rtsx_pci_writel(pcr, RTSX_BIER, 0); @@ -1680,9 +1631,6 @@
> > > > > > static void rtsx_pci_remove(struct pci_dev *pcidev)
> > > > > >       spin_unlock_irq(&pcr->lock);
> > > > > >
> > > > > >       cancel_delayed_work_sync(&pcr->carddet_work);
> > > > > > -     cancel_delayed_work_sync(&pcr->idle_work);
> > > > > > -     if (pcr->rtd3_en)
> > > > > > -             cancel_delayed_work_sync(&pcr->rtd3_work);
> > > > > >
> > > > > >       mfd_remove_devices(&pcidev->dev);
> > > > > >
> > > > > > @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct
> > > > > > pci_dev
> > > > > > *pcidev)
> > > > > >       idr_remove(&rtsx_pci_idr, pcr->id);
> > > > > >       spin_unlock(&rtsx_pci_lock);
> > > > > >
> > > > > > -     if (pcr->rtd3_en) {
> > > > > > -             pm_runtime_disable(&pcr->pci->dev);
> > > > > > -             pm_runtime_put_noidle(&pcr->pci->dev);
> > > > > > -     }
> > > > > > -
> > > > > >       kfree(pcr->slots);
> > > > > >       kfree(pcr);
> > > > > >       kfree(handle);
> > > > > > @@ -1726,7 +1669,6 @@ static int __maybe_unused
> > > > > > rtsx_pci_suspend(struct device *dev_d)
> > > > > >       pcr = handle->pcr;
> > > > > >
> > > > > >       cancel_delayed_work(&pcr->carddet_work);
> > > > > > -     cancel_delayed_work(&pcr->idle_work);
> > > > > >
> > > > > >       mutex_lock(&pcr->pcr_mutex);
> > > > > >
> > > > > > @@ -1760,8 +1702,6 @@ static int __maybe_unused
> > > > > > rtsx_pci_resume(struct device *dev_d)
> > > > > >       if (ret)
> > > > > >               goto out;
> > > > > >
> > > > > > -     schedule_delayed_work(&pcr->idle_work,
> > msecs_to_jiffies(200));
> > > > > > -
> > > > > >  out:
> > > > > >       mutex_unlock(&pcr->pcr_mutex);
> > > > > >       return ret;
> > > > > > @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct
> > > > > > pci_dev
> > > > > > *pcidev)
> > > > > >               pci_disable_msi(pcr->pci);  }
> > > > > >
> > > > > > +static int rtsx_pci_runtime_idle(struct device *device) {
> > > > > > +     struct pci_dev *pcidev = to_pci_dev(device);
> > > > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > > > > +
> > > > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > > > +
> > > > > > +     mutex_lock(&pcr->pcr_mutex);
> > > > > > +
> > > > > > +     pcr->state = PDEV_STAT_IDLE;
> > > > > > +
> > > > > > +     if (pcr->ops->disable_auto_blink)
> > > > > > +             pcr->ops->disable_auto_blink(pcr);
> > > > > > +     if (pcr->ops->turn_off_led)
> > > > > > +             pcr->ops->turn_off_led(pcr);
> > > > > > +
> > > > > > +     rtsx_pm_power_saving(pcr);
> > > > > > +
> > > > > > +     mutex_unlock(&pcr->pcr_mutex);
> > > > > > +
> > > > > > +     if (pcr->rtd3_en)
> > > > > > +             pm_schedule_suspend(device, 5000);
> > > > > > +
> > > > > > +     return -EBUSY;
> > > > > > +}
> > > > > > +
> > > > > >  static int rtsx_pci_runtime_suspend(struct device *device)  {
> > > > > >       struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31
> > > > > > +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device
> > > > > > *device)
> > > > > >
> > > > > >       handle = pci_get_drvdata(pcidev);
> > > > > >       pcr = handle->pcr;
> > > > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > > > >
> > > > > > -     cancel_delayed_work(&pcr->carddet_work);
> > > > > > -     cancel_delayed_work(&pcr->rtd3_work);
> > > > > > -     cancel_delayed_work(&pcr->idle_work);
> > > > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > > > +
> > > > > > +     cancel_delayed_work_sync(&pcr->carddet_work);
> > > > > >
> > > > > >       mutex_lock(&pcr->pcr_mutex);
> > > > > >       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> > > > > >
> > > > > >       mutex_unlock(&pcr->pcr_mutex);
> > > > > >
> > > > > > -     pcr->is_runtime_suspended = true;
> > > > > > -
> > > > > >       return 0;
> > > > > >  }
> > > > > >
> > > > > >  static int rtsx_pci_runtime_resume(struct device *device)  {
> > > > > >       struct pci_dev *pcidev = to_pci_dev(device);
> > > > > > -     struct pcr_handle *handle;
> > > > > > -     struct rtsx_pcr *pcr;
> > > > > > +     struct pcr_handle *handle = pci_get_drvdata(pcidev);
> > > > > > +     struct rtsx_pcr *pcr = handle->pcr;
> > > > > >
> > > > > > -     handle = pci_get_drvdata(pcidev);
> > > > > > -     pcr = handle->pcr;
> > > > > > -     dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> > > > > > +     dev_dbg(device, "--> %s\n", __func__);
> > > > > >
> > > > > >       mutex_lock(&pcr->pcr_mutex);
> > > > > >
> > > > > > @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct
> > > > > > device
> > > > > > *device)
> > > > > >
> > pcr->slots[RTSX_SD_CARD].p_dev);
> > > > > >       }
> > > > > >
> > > > > > -     schedule_delayed_work(&pcr->idle_work,
> > msecs_to_jiffies(200));
> > > > > > -
> > > > > >       mutex_unlock(&pcr->pcr_mutex);
> > > > > >       return 0;
> > > > > >  }
> > > > > > @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct
> > > > > > device
> > > > > > *device)
> > > > > >
> > > > > >  static const struct dev_pm_ops rtsx_pci_pm_ops = {
> > > > > >       SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend,
> > rtsx_pci_resume)
> > > > > > -     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > > > rtsx_pci_runtime_resume, NULL)
> > > > > > +     SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> > > > > > rtsx_pci_runtime_resume,
> > > > > > +rtsx_pci_runtime_idle)
> > > > > >  };
> > > > > >
> > > > > >  static struct pci_driver rtsx_pci_driver = { diff --git
> > > > > > a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> > > > > > 4ab7bfc675f11..89b7d34e25b63 100644
> > > > > > --- a/include/linux/rtsx_pci.h
> > > > > > +++ b/include/linux/rtsx_pci.h
> > > > > > @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
> > > > > >       unsigned int                    card_exist;
> > > > > >
> > > > > >       struct delayed_work             carddet_work;
> > > > > > -     struct delayed_work             idle_work;
> > > > > > -     struct delayed_work             rtd3_work;
> > > > > >
> > > > > >       spinlock_t                      lock;
> > > > > >       struct mutex                    pcr_mutex;
> > > > > > @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
> > > > > >       unsigned int                    cur_clock;
> > > > > >       bool                            remove_pci;
> > > > > >       bool                            msi_en;
> > > > > > -     bool                            is_runtime_suspended;
> > > > > >
> > > > > >  #define EXTRA_CAPS_SD_SDR50          (1 << 0)
> > > > > >  #define EXTRA_CAPS_SD_SDR104         (1 << 1)
> > > > > > --
> > > > > > 2.33.1
> > > > >
> > > > ------Please consider the environment before printing this e-mail.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
  2022-01-21  3:57     ` Ricky WU
  2022-01-21  6:31     ` [PATCH v3 " Kai-Heng Feng
@ 2022-01-24  5:47     ` Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
                         ` (2 more replies)
  2022-01-24  7:28     ` [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  4 siblings, 3 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  5:47 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
weird tricks to keep it from runtime suspending.

So use those helpers at right places to properly manage runtime PM.

Since rtsx_pci will handle the real power management, remove
MMC_CAP_AGGRESSIVE_PM to avoid doing duplicate work.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v4:
 - Decrease the autosuspend delay to 200ms for more power saving.

v3:
v2:
 - No change.

 drivers/mmc/host/rtsx_pci_sdmmc.c | 47 ++++++++++++++++++++++---------
 1 file changed, 33 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 58cfaffa3c2d8..4c7931b053aad 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -806,6 +806,7 @@ static void sd_request(struct work_struct *work)
 	struct mmc_request *mrq = host->mrq;
 	struct mmc_command *cmd = mrq->cmd;
 	struct mmc_data *data = mrq->data;
+	struct device *dev = &host->pdev->dev;
 
 	unsigned int data_size = 0;
 	int err;
@@ -822,6 +823,7 @@ static void sd_request(struct work_struct *work)
 	}
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -858,6 +860,8 @@ static void sd_request(struct work_struct *work)
 			data->bytes_xfered = data->blocks * data->blksz;
 	}
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 finish:
@@ -1080,6 +1084,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 
 	if (host->eject)
 		return;
@@ -1088,6 +1093,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		return;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1121,6 +1127,8 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth,
 			host->initial_mode, host->double_clk, host->vpclk);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 }
 
@@ -1128,6 +1136,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int ro = 0;
 	u32 val;
 
@@ -1135,6 +1144,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 		return -ENOMEDIUM;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1144,6 +1154,8 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 	if (val & SD_WRITE_PROTECT)
 		ro = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return ro;
@@ -1153,6 +1165,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int cd = 0;
 	u32 val;
 
@@ -1160,6 +1173,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 		return cd;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1169,6 +1183,8 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 	if (val & SD_EXIST)
 		cd = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return cd;
@@ -1251,6 +1267,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 	u8 voltage;
 
@@ -1265,6 +1282,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1294,6 +1312,8 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 	err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
 			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1303,6 +1323,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 
 	if (host->eject)
@@ -1313,6 +1334,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1345,6 +1367,8 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true);
 
 out:
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1427,7 +1451,6 @@ static void init_extra_caps(struct realtek_pci_sdmmc *host)
 static void realtek_init_host(struct realtek_pci_sdmmc *host)
 {
 	struct mmc_host *mmc = host->mmc;
-	struct rtsx_pcr *pcr = host->pcr;
 
 	mmc->f_min = 250000;
 	mmc->f_max = 208000000;
@@ -1435,8 +1458,6 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host)
 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
 		MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
 		MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
-	if (pcr->rtd3_en)
-		mmc->caps = mmc->caps | MMC_CAP_AGGRESSIVE_PM;
 	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
 		MMC_CAP2_NO_SDIO;
 	mmc->max_current_330 = 400;
@@ -1495,12 +1516,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
 
 	realtek_init_host(host);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
-		pm_runtime_use_autosuspend(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
-	}
-
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 200);
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_use_autosuspend(&pdev->dev);
 
 	mmc_add_host(mmc);
 
@@ -1521,11 +1542,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
 	mmc = host->mmc;
 
-	if (pcr->rtd3_en) {
-		pm_runtime_dont_use_autosuspend(&pdev->dev);
-		pm_runtime_disable(&pdev->dev);
-	}
-
 	cancel_work_sync(&host->work);
 
 	mutex_lock(&host->host_mutex);
@@ -1548,6 +1564,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 
 	flush_work(&host->work);
 
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	mmc_free_host(mmc);
 
 	dev_dbg(&(pdev->dev),
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v4 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-24  5:47     ` [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
@ 2022-01-24  5:47       ` Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  5:47 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
uses "rtd3_work" and "idle_work" to manage it's own runtime PM state
machine.

When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
correctly, all the additional works can be managed by generic runtime PM
helpers.

So consolidate "idle_work" and "rtd3_work" into generic runtime idle
callback and runtime suspend callback, respectively.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v4:
 - No change.

v3:
 - Allow runtime PM for all devices, but only schedule runtime suspend
   for devices with rtd3_en flagged.

v2:
 - Remove unused idle_work and rtd3_work from rtsx_pcr.

 drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
 include/linux/rtsx_pci.h           |   3 -
 2 files changed, 39 insertions(+), 82 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 6ac509c1821c9..f919290f01192 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
 	if (pcr->remove_pci)
 		return;
 
-	if (pcr->rtd3_en)
-		if (pcr->is_runtime_suspended) {
-			pm_runtime_get(&(pcr->pci->dev));
-			pcr->is_runtime_suspended = false;
-		}
-
 	if (pcr->state != PDEV_STAT_RUN) {
 		pcr->state = PDEV_STAT_RUN;
 		if (pcr->ops->enable_auto_blink)
 			pcr->ops->enable_auto_blink(pcr);
 		rtsx_pm_full_on(pcr);
 	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-	if (!pcr->is_runtime_suspended)
-		pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if (pcr->rtd3_en)
-		mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
 static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 {
 	/* Set relink_time to 0 */
@@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 	pcr->card_inserted = 0;
 	pcr->card_removed = 0;
 	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
 	pcr->msi_en = msi_en;
 	if (pcr->msi_en) {
@@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
 	}
 
-	if (pcr->rtd3_en) {
-		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-		pm_runtime_allow(&pcidev->dev);
-		pm_runtime_enable(&pcidev->dev);
-		pcr->is_runtime_suspended = false;
-	}
-
 
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
 		goto free_slots;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+	pm_runtime_allow(&pcidev->dev);
+	pm_runtime_put(&pcidev->dev);
 
 	return 0;
 
@@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	struct pcr_handle *handle = pci_get_drvdata(pcidev);
 	struct rtsx_pcr *pcr = handle->pcr;
 
-	if (pcr->rtd3_en)
-		pm_runtime_get_noresume(&pcr->pci->dev);
-
 	pcr->remove_pci = true;
 
+	pm_runtime_get_sync(&pcidev->dev);
+	pm_runtime_forbid(&pcidev->dev);
+
 	/* Disable interrupts at the pcr level */
 	spin_lock_irq(&pcr->lock);
 	rtsx_pci_writel(pcr, RTSX_BIER, 0);
@@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	spin_unlock_irq(&pcr->lock);
 
 	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-	if (pcr->rtd3_en)
-		cancel_delayed_work_sync(&pcr->rtd3_work);
 
 	mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	idr_remove(&rtsx_pci_idr, pcr->id);
 	spin_unlock(&rtsx_pci_lock);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_disable(&pcr->pci->dev);
-		pm_runtime_put_noidle(&pcr->pci->dev);
-	}
-
 	kfree(pcr->slots);
 	kfree(pcr);
 	kfree(handle);
@@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	pcr = handle->pcr;
 
 	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 	if (ret)
 		goto out;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
 	mutex_unlock(&pcr->pcr_mutex);
 	return ret;
@@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 		pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+	struct pci_dev *pcidev = to_pci_dev(device);
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	if (pcr->rtd3_en)
+		pm_schedule_suspend(device, 5000);
+
+	return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
@@ -1794,31 +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->rtd3_work);
-	cancel_delayed_work(&pcr->idle_work);
+	dev_dbg(device, "--> %s\n", __func__);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
-	pcr->is_runtime_suspended = true;
-
 	return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+	dev_dbg(device, "--> %s\n", __func__);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 				pcr->slots[RTSX_SD_CARD].p_dev);
 	}
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 4ab7bfc675f11..89b7d34e25b63 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1201,8 +1201,6 @@ struct rtsx_pcr {
 	unsigned int			card_exist;
 
 	struct delayed_work		carddet_work;
-	struct delayed_work		idle_work;
-	struct delayed_work		rtd3_work;
 
 	spinlock_t			lock;
 	struct mutex			pcr_mutex;
@@ -1212,7 +1210,6 @@ struct rtsx_pcr {
 	unsigned int			cur_clock;
 	bool				remove_pci;
 	bool				msi_en;
-	bool				is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50		(1 << 0)
 #define EXTRA_CAPS_SD_SDR104		(1 << 1)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v4 3/4] misc: rtsx: Cleanup power management ops
  2022-01-24  5:47     ` [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
@ 2022-01-24  5:47       ` Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  5:47 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

- Use cancel_delayed_work_sync to ensure there's no race with
  carddet_work.

- Remove device_wakeup_disable to save some CPU cycles. If the device
  really has ACPI _DSW then the wakeup should be disabled in probe
  routine.

- Remove fetch_vendor_settings from runtime resume routine, since they
  are already saved in "struct rtsx_pcr".

- Move variable assignments to the top of the functions.

Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v4:
  - Move variable assignments to the top of the functions.

v3:
v2:
 - No change.

 drivers/misc/cardreader/rtsx_pcr.c | 34 ++++++++----------------------
 1 file changed, 9 insertions(+), 25 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index f919290f01192..ec395a33faf8b 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1660,22 +1660,17 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 {
 	struct pci_dev *pcidev = to_pci_dev(dev_d);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
-	cancel_delayed_work(&pcr->carddet_work);
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
-	device_wakeup_disable(dev_d);
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1683,15 +1678,12 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 {
 	struct pci_dev *pcidev = to_pci_dev(dev_d);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 	int ret = 0;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
 	mutex_lock(&pcr->pcr_mutex);
 
 	ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
@@ -1711,13 +1703,11 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 
 static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 {
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
 	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
 
 	pci_disable_device(pcidev);
@@ -1756,11 +1746,8 @@ static int rtsx_pci_runtime_idle(struct device *device)
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
-
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(device, "--> %s\n", __func__);
 
@@ -1786,9 +1773,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
 
-	if (pcr->ops->fetch_vendor_settings)
-		pcr->ops->fetch_vendor_settings(pcr);
-
 	rtsx_pci_init_hw(pcr);
 
 	if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) {
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v4 4/4] misc: rtsx: Quiesce rts5249 on system suspend
  2022-01-24  5:47     ` [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
  2022-01-24  5:47       ` [PATCH v4 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
@ 2022-01-24  5:47       ` Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  5:47 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Set more registers in force_power_down callback to avoid S3 wakeup from
hotplugging cards.

This is originally written by Ricky WU.

Link: https://lore.kernel.org/lkml/c4525b4738f94483b9b8f8571fc80646@realtek.com/
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v4:
v3:
v2:
 - No change.

 drivers/misc/cardreader/rtl8411.c  |  2 +-
 drivers/misc/cardreader/rts5209.c  |  2 +-
 drivers/misc/cardreader/rts5228.c  |  2 +-
 drivers/misc/cardreader/rts5229.c  |  2 +-
 drivers/misc/cardreader/rts5249.c  | 31 ++++++++++++++++++++++++++++--
 drivers/misc/cardreader/rts5261.c  |  2 +-
 drivers/misc/cardreader/rtsx_pcr.c | 14 +++++++-------
 drivers/misc/cardreader/rtsx_pcr.h |  1 +
 include/linux/rtsx_pci.h           |  2 +-
 9 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/cardreader/rtl8411.c b/drivers/misc/cardreader/rtl8411.c
index 4c5621b17a6fb..06457e875a90c 100644
--- a/drivers/misc/cardreader/rtl8411.c
+++ b/drivers/misc/cardreader/rtl8411.c
@@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c
index 29f5414072bf1..52b0a476ba51f 100644
--- a/drivers/misc/cardreader/rts5209.c
+++ b/drivers/misc/cardreader/rts5209.c
@@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	}
 }
 
-static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c
index ffc128278613b..ffe3afbf8bfed 100644
--- a/drivers/misc/cardreader/rts5228.c
+++ b/drivers/misc/cardreader/rts5228.c
@@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
 	return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
 }
 
-static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rts5229.c b/drivers/misc/cardreader/rts5229.c
index c748eaf1ec1f9..b0edd8006d52f 100644
--- a/drivers/misc/cardreader/rts5229.c
+++ b/drivers/misc/cardreader/rts5229.c
@@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
 }
diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c
index 53f3a1f45c4a7..91d240dd68faa 100644
--- a/drivers/misc/cardreader/rts5249.c
+++ b/drivers/misc/cardreader/rts5249.c
@@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
 	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
 
-	pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+		pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
 
 	if (rtsx_check_mmc_support(reg))
 		pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
@@ -143,6 +144,27 @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
 	return 0;
 }
 
+static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+	/* Set relink_time to 0 */
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+				RELINK_TIME_MASK, 0);
+
+	rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+	if (!runtime) {
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+				CD_RESUME_EN_MASK, 0);
+		rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00);
+		rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20);
+	}
+
+	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
 static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr)
 {
 	u8 cnt, sv;
@@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 
 	rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
 
-	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
 		rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN);
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+			CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+	}
 
 	if (pcr->rtd3_en) {
 		if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
@@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
 	.card_power_on = rtsx_base_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rtsx_base_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
@@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
 	.card_power_on = rts525a_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rts525a_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 1fd4e0e507302..64333347c14a4 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg);
 }
 
-static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index ec395a33faf8b..7262ef0f1913f 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1086,7 +1086,7 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtsx_base_force_power_down(struct rtsx_pcr *pcr)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -1100,7 +1100,7 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
 }
 
-static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	if (pcr->ops->turn_off_led)
 		pcr->ops->turn_off_led(pcr);
@@ -1112,9 +1112,9 @@ static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
 
 	if (pcr->ops->force_power_down)
-		pcr->ops->force_power_down(pcr, pm_state);
+		pcr->ops->force_power_down(pcr, pm_state, runtime);
 	else
-		rtsx_base_force_power_down(pcr, pm_state);
+		rtsx_base_force_power_down(pcr);
 }
 
 void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
@@ -1669,7 +1669,7 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 
 	mutex_lock(&pcr->pcr_mutex);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, false);
 
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
@@ -1708,7 +1708,7 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S1, false);
 
 	pci_disable_device(pcidev);
 	free_irq(pcr->irq, (void *)pcr);
@@ -1754,7 +1754,7 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, true);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
index daf057c4eea62..aa0ebd6672277 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -25,6 +25,7 @@
 #define REG_EFUSE_POWEROFF		0x00
 #define RTS5250_CLK_CFG3		0xFF79
 #define RTS525A_CFG_MEM_PD		0xF0
+#define RTS524A_AUTOLOAD_CFG1		0xFF7C
 #define RTS524A_PM_CTRL3		0xFF7E
 #define RTS525A_BIOS_CFG		0xFF2D
 #define RTS525A_LOAD_BIOS_FLAG	0x01
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 89b7d34e25b63..3d780b44e678a 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1095,7 +1095,7 @@ struct pcr_ops {
 	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
 	int		(*conv_clk_and_div_n)(int clk, int dir);
 	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
-	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
+	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime);
 	void		(*stop_cmd)(struct rtsx_pcr *pcr);
 
 	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
                       ` (2 preceding siblings ...)
  2022-01-24  5:47     ` [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
@ 2022-01-24  7:28     ` Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
                         ` (2 more replies)
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  4 siblings, 3 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  7:28 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
weird tricks to keep it from runtime suspending.

So use those helpers at right places to properly manage runtime PM.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v5:
 - Revert back to v3 as Realtek suggested.

v4:
 - Decrease the autosuspend delay to 200ms for more power saving.

v3:
v2:
 - No change.

 drivers/mmc/host/rtsx_pci_sdmmc.c | 44 +++++++++++++++++++++++--------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 58cfaffa3c2d8..2656dc840a3a5 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -806,6 +806,7 @@ static void sd_request(struct work_struct *work)
 	struct mmc_request *mrq = host->mrq;
 	struct mmc_command *cmd = mrq->cmd;
 	struct mmc_data *data = mrq->data;
+	struct device *dev = &host->pdev->dev;
 
 	unsigned int data_size = 0;
 	int err;
@@ -822,6 +823,7 @@ static void sd_request(struct work_struct *work)
 	}
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -858,6 +860,8 @@ static void sd_request(struct work_struct *work)
 			data->bytes_xfered = data->blocks * data->blksz;
 	}
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 finish:
@@ -1080,6 +1084,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 
 	if (host->eject)
 		return;
@@ -1088,6 +1093,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		return;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1121,6 +1127,8 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth,
 			host->initial_mode, host->double_clk, host->vpclk);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 }
 
@@ -1128,6 +1136,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int ro = 0;
 	u32 val;
 
@@ -1135,6 +1144,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 		return -ENOMEDIUM;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1144,6 +1154,8 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 	if (val & SD_WRITE_PROTECT)
 		ro = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return ro;
@@ -1153,6 +1165,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int cd = 0;
 	u32 val;
 
@@ -1160,6 +1173,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 		return cd;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1169,6 +1183,8 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 	if (val & SD_EXIST)
 		cd = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return cd;
@@ -1251,6 +1267,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 	u8 voltage;
 
@@ -1265,6 +1282,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1294,6 +1312,8 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 	err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
 			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1303,6 +1323,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 
 	if (host->eject)
@@ -1313,6 +1334,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1345,6 +1367,8 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true);
 
 out:
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1495,12 +1519,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
 
 	realtek_init_host(host);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
-		pm_runtime_use_autosuspend(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
-	}
-
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_use_autosuspend(&pdev->dev);
 
 	mmc_add_host(mmc);
 
@@ -1521,11 +1545,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
 	mmc = host->mmc;
 
-	if (pcr->rtd3_en) {
-		pm_runtime_dont_use_autosuspend(&pdev->dev);
-		pm_runtime_disable(&pdev->dev);
-	}
-
 	cancel_work_sync(&host->work);
 
 	mutex_lock(&host->host_mutex);
@@ -1548,6 +1567,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 
 	flush_work(&host->work);
 
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	mmc_free_host(mmc);
 
 	dev_dbg(&(pdev->dev),
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-24  7:28     ` [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
@ 2022-01-24  7:28       ` Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  7:28 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
uses "rtd3_work" and "idle_work" to manage it's own runtime PM state
machine.

When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
correctly, all the additional works can be managed by generic runtime PM
helpers.

So consolidate "idle_work" and "rtd3_work" into generic runtime idle
callback and runtime suspend callback, respectively.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v5:
v4:
 - No change.

v3:
 - Allow runtime PM for all devices, but only schedule runtime suspend
   for devices with rtd3_en flagged.

v2:
 - Remove unused idle_work and rtd3_work from rtsx_pcr.

 drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
 include/linux/rtsx_pci.h           |   3 -
 2 files changed, 39 insertions(+), 82 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 6ac509c1821c9..f919290f01192 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
 	if (pcr->remove_pci)
 		return;
 
-	if (pcr->rtd3_en)
-		if (pcr->is_runtime_suspended) {
-			pm_runtime_get(&(pcr->pci->dev));
-			pcr->is_runtime_suspended = false;
-		}
-
 	if (pcr->state != PDEV_STAT_RUN) {
 		pcr->state = PDEV_STAT_RUN;
 		if (pcr->ops->enable_auto_blink)
 			pcr->ops->enable_auto_blink(pcr);
 		rtsx_pm_full_on(pcr);
 	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-	if (!pcr->is_runtime_suspended)
-		pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if (pcr->rtd3_en)
-		mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
 static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 {
 	/* Set relink_time to 0 */
@@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 	pcr->card_inserted = 0;
 	pcr->card_removed = 0;
 	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
 	pcr->msi_en = msi_en;
 	if (pcr->msi_en) {
@@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
 	}
 
-	if (pcr->rtd3_en) {
-		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-		pm_runtime_allow(&pcidev->dev);
-		pm_runtime_enable(&pcidev->dev);
-		pcr->is_runtime_suspended = false;
-	}
-
 
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
 		goto free_slots;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+	pm_runtime_allow(&pcidev->dev);
+	pm_runtime_put(&pcidev->dev);
 
 	return 0;
 
@@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	struct pcr_handle *handle = pci_get_drvdata(pcidev);
 	struct rtsx_pcr *pcr = handle->pcr;
 
-	if (pcr->rtd3_en)
-		pm_runtime_get_noresume(&pcr->pci->dev);
-
 	pcr->remove_pci = true;
 
+	pm_runtime_get_sync(&pcidev->dev);
+	pm_runtime_forbid(&pcidev->dev);
+
 	/* Disable interrupts at the pcr level */
 	spin_lock_irq(&pcr->lock);
 	rtsx_pci_writel(pcr, RTSX_BIER, 0);
@@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	spin_unlock_irq(&pcr->lock);
 
 	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-	if (pcr->rtd3_en)
-		cancel_delayed_work_sync(&pcr->rtd3_work);
 
 	mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	idr_remove(&rtsx_pci_idr, pcr->id);
 	spin_unlock(&rtsx_pci_lock);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_disable(&pcr->pci->dev);
-		pm_runtime_put_noidle(&pcr->pci->dev);
-	}
-
 	kfree(pcr->slots);
 	kfree(pcr);
 	kfree(handle);
@@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	pcr = handle->pcr;
 
 	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 	if (ret)
 		goto out;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
 	mutex_unlock(&pcr->pcr_mutex);
 	return ret;
@@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 		pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+	struct pci_dev *pcidev = to_pci_dev(device);
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	if (pcr->rtd3_en)
+		pm_schedule_suspend(device, 5000);
+
+	return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
@@ -1794,31 +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->rtd3_work);
-	cancel_delayed_work(&pcr->idle_work);
+	dev_dbg(device, "--> %s\n", __func__);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
-	pcr->is_runtime_suspended = true;
-
 	return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+	dev_dbg(device, "--> %s\n", __func__);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 				pcr->slots[RTSX_SD_CARD].p_dev);
 	}
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 4ab7bfc675f11..89b7d34e25b63 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1201,8 +1201,6 @@ struct rtsx_pcr {
 	unsigned int			card_exist;
 
 	struct delayed_work		carddet_work;
-	struct delayed_work		idle_work;
-	struct delayed_work		rtd3_work;
 
 	spinlock_t			lock;
 	struct mutex			pcr_mutex;
@@ -1212,7 +1210,6 @@ struct rtsx_pcr {
 	unsigned int			cur_clock;
 	bool				remove_pci;
 	bool				msi_en;
-	bool				is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50		(1 << 0)
 #define EXTRA_CAPS_SD_SDR104		(1 << 1)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 3/4] misc: rtsx: Cleanup power management ops
  2022-01-24  7:28     ` [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
@ 2022-01-24  7:28       ` Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  7:28 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Yang Li, Christophe JAILLET,
	linux-kernel

- Use cancel_delayed_work_sync to ensure there's no race with
  carddet_work.

- Remove device_wakeup_disable to save some CPU cycles. If the device
  really has ACPI _DSW then the wakeup should be disabled in probe
  routine.

- Remove fetch_vendor_settings from runtime resume routine, since they
  are already saved in "struct rtsx_pcr".

- Move variable assignments to the top of the functions.

Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v5:
 - No change.

v4:
 - Move variable assignments to the top of the functions.

v3:
v2:
 - No change.

 drivers/misc/cardreader/rtsx_pcr.c | 34 ++++++++----------------------
 1 file changed, 9 insertions(+), 25 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index f919290f01192..ec395a33faf8b 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1660,22 +1660,17 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 {
 	struct pci_dev *pcidev = to_pci_dev(dev_d);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
-	cancel_delayed_work(&pcr->carddet_work);
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
-	device_wakeup_disable(dev_d);
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1683,15 +1678,12 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 {
 	struct pci_dev *pcidev = to_pci_dev(dev_d);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 	int ret = 0;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
 	mutex_lock(&pcr->pcr_mutex);
 
 	ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
@@ -1711,13 +1703,11 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 
 static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 {
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
 	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
 
 	pci_disable_device(pcidev);
@@ -1756,11 +1746,8 @@ static int rtsx_pci_runtime_idle(struct device *device)
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
-
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(device, "--> %s\n", __func__);
 
@@ -1786,9 +1773,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
 
-	if (pcr->ops->fetch_vendor_settings)
-		pcr->ops->fetch_vendor_settings(pcr);
-
 	rtsx_pci_init_hw(pcr);
 
 	if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) {
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 4/4] misc: rtsx: Quiesce rts5249 on system suspend
  2022-01-24  7:28     ` [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
  2022-01-24  7:28       ` [PATCH v5 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
@ 2022-01-24  7:28       ` Kai-Heng Feng
  2 siblings, 0 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-24  7:28 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

Set more registers in force_power_down callback to avoid S3 wakeup from
hotplugging cards.

This is originally written by Ricky WU.

Link: https://lore.kernel.org/lkml/c4525b4738f94483b9b8f8571fc80646@realtek.com/
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v5:
v4:
v3:
v2:
 - No change.

 drivers/misc/cardreader/rtl8411.c  |  2 +-
 drivers/misc/cardreader/rts5209.c  |  2 +-
 drivers/misc/cardreader/rts5228.c  |  2 +-
 drivers/misc/cardreader/rts5229.c  |  2 +-
 drivers/misc/cardreader/rts5249.c  | 31 ++++++++++++++++++++++++++++--
 drivers/misc/cardreader/rts5261.c  |  2 +-
 drivers/misc/cardreader/rtsx_pcr.c | 14 +++++++-------
 drivers/misc/cardreader/rtsx_pcr.h |  1 +
 include/linux/rtsx_pci.h           |  2 +-
 9 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/cardreader/rtl8411.c b/drivers/misc/cardreader/rtl8411.c
index 4c5621b17a6fb..06457e875a90c 100644
--- a/drivers/misc/cardreader/rtl8411.c
+++ b/drivers/misc/cardreader/rtl8411.c
@@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c
index 29f5414072bf1..52b0a476ba51f 100644
--- a/drivers/misc/cardreader/rts5209.c
+++ b/drivers/misc/cardreader/rts5209.c
@@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	}
 }
 
-static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c
index ffc128278613b..ffe3afbf8bfed 100644
--- a/drivers/misc/cardreader/rts5228.c
+++ b/drivers/misc/cardreader/rts5228.c
@@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
 	return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
 }
 
-static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rts5229.c b/drivers/misc/cardreader/rts5229.c
index c748eaf1ec1f9..b0edd8006d52f 100644
--- a/drivers/misc/cardreader/rts5229.c
+++ b/drivers/misc/cardreader/rts5229.c
@@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
 }
diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c
index 53f3a1f45c4a7..91d240dd68faa 100644
--- a/drivers/misc/cardreader/rts5249.c
+++ b/drivers/misc/cardreader/rts5249.c
@@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
 	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
 
-	pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+		pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
 
 	if (rtsx_check_mmc_support(reg))
 		pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
@@ -143,6 +144,27 @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
 	return 0;
 }
 
+static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+	/* Set relink_time to 0 */
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+				RELINK_TIME_MASK, 0);
+
+	rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+	if (!runtime) {
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+				CD_RESUME_EN_MASK, 0);
+		rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00);
+		rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20);
+	}
+
+	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
 static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr)
 {
 	u8 cnt, sv;
@@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 
 	rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
 
-	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
 		rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN);
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+			CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+	}
 
 	if (pcr->rtd3_en) {
 		if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
@@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
 	.card_power_on = rtsx_base_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rtsx_base_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
@@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
 	.card_power_on = rts525a_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rts525a_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 1fd4e0e507302..64333347c14a4 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg);
 }
 
-static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index ec395a33faf8b..7262ef0f1913f 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1086,7 +1086,7 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtsx_base_force_power_down(struct rtsx_pcr *pcr)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -1100,7 +1100,7 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
 }
 
-static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	if (pcr->ops->turn_off_led)
 		pcr->ops->turn_off_led(pcr);
@@ -1112,9 +1112,9 @@ static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
 
 	if (pcr->ops->force_power_down)
-		pcr->ops->force_power_down(pcr, pm_state);
+		pcr->ops->force_power_down(pcr, pm_state, runtime);
 	else
-		rtsx_base_force_power_down(pcr, pm_state);
+		rtsx_base_force_power_down(pcr);
 }
 
 void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
@@ -1669,7 +1669,7 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 
 	mutex_lock(&pcr->pcr_mutex);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, false);
 
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
@@ -1708,7 +1708,7 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S1, false);
 
 	pci_disable_device(pcidev);
 	free_irq(pcr->irq, (void *)pcr);
@@ -1754,7 +1754,7 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, true);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
index daf057c4eea62..aa0ebd6672277 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -25,6 +25,7 @@
 #define REG_EFUSE_POWEROFF		0x00
 #define RTS5250_CLK_CFG3		0xFF79
 #define RTS525A_CFG_MEM_PD		0xF0
+#define RTS524A_AUTOLOAD_CFG1		0xFF7C
 #define RTS524A_PM_CTRL3		0xFF7E
 #define RTS525A_BIOS_CFG		0xFF2D
 #define RTS525A_LOAD_BIOS_FLAG	0x01
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 89b7d34e25b63..3d780b44e678a 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1095,7 +1095,7 @@ struct pcr_ops {
 	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
 	int		(*conv_clk_and_div_n)(int clk, int dir);
 	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
-	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
+	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime);
 	void		(*stop_cmd)(struct rtsx_pcr *pcr);
 
 	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
                       ` (3 preceding siblings ...)
  2022-01-24  7:28     ` [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
@ 2022-01-25  5:50     ` Kai-Heng Feng
  2022-01-25  5:50       ` [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
                         ` (4 more replies)
  4 siblings, 5 replies; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-25  5:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
weird tricks to keep it from runtime suspending.

So use those helpers at right places to properly manage runtime PM.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v6:
 - Change the auto suspend delay to 200ms as Realtek suggested.

v5:
 - Revert back to v3 as Realtek suggested.

v4:
 - Decrease the autosuspend delay to 200ms for more power saving.

v3:
v2:
 - No change.

 drivers/mmc/host/rtsx_pci_sdmmc.c | 44 +++++++++++++++++++++++--------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 58cfaffa3c2d8..2a3f14afe9f83 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -806,6 +806,7 @@ static void sd_request(struct work_struct *work)
 	struct mmc_request *mrq = host->mrq;
 	struct mmc_command *cmd = mrq->cmd;
 	struct mmc_data *data = mrq->data;
+	struct device *dev = &host->pdev->dev;
 
 	unsigned int data_size = 0;
 	int err;
@@ -822,6 +823,7 @@ static void sd_request(struct work_struct *work)
 	}
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -858,6 +860,8 @@ static void sd_request(struct work_struct *work)
 			data->bytes_xfered = data->blocks * data->blksz;
 	}
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 finish:
@@ -1080,6 +1084,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 
 	if (host->eject)
 		return;
@@ -1088,6 +1093,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		return;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1121,6 +1127,8 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth,
 			host->initial_mode, host->double_clk, host->vpclk);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 }
 
@@ -1128,6 +1136,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int ro = 0;
 	u32 val;
 
@@ -1135,6 +1144,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 		return -ENOMEDIUM;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1144,6 +1154,8 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
 	if (val & SD_WRITE_PROTECT)
 		ro = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return ro;
@@ -1153,6 +1165,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int cd = 0;
 	u32 val;
 
@@ -1160,6 +1173,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 		return cd;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1169,6 +1183,8 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
 	if (val & SD_EXIST)
 		cd = 1;
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return cd;
@@ -1251,6 +1267,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 	u8 voltage;
 
@@ -1265,6 +1282,7 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1294,6 +1312,8 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 	err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
 			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
 
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1303,6 +1323,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	struct rtsx_pcr *pcr = host->pcr;
+	struct device *dev = &host->pdev->dev;
 	int err = 0;
 
 	if (host->eject)
@@ -1313,6 +1334,7 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		return err;
 
 	mutex_lock(&pcr->pcr_mutex);
+	pm_runtime_get_sync(dev);
 
 	rtsx_pci_start_run(pcr);
 
@@ -1345,6 +1367,8 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true);
 
 out:
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 	mutex_unlock(&pcr->pcr_mutex);
 
 	return err;
@@ -1495,12 +1519,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
 
 	realtek_init_host(host);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
-		pm_runtime_use_autosuspend(&pdev->dev);
-		pm_runtime_enable(&pdev->dev);
-	}
-
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 200);
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_use_autosuspend(&pdev->dev);
 
 	mmc_add_host(mmc);
 
@@ -1521,11 +1545,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
 	mmc = host->mmc;
 
-	if (pcr->rtd3_en) {
-		pm_runtime_dont_use_autosuspend(&pdev->dev);
-		pm_runtime_disable(&pdev->dev);
-	}
-
 	cancel_work_sync(&host->work);
 
 	mutex_lock(&host->host_mutex);
@@ -1548,6 +1567,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 
 	flush_work(&host->work);
 
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	mmc_free_host(mmc);
 
 	dev_dbg(&(pdev->dev),
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
@ 2022-01-25  5:50       ` Kai-Heng Feng
  2022-01-25  6:38         ` Ricky WU
  2022-01-25  5:50       ` [PATCH v6 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
                         ` (3 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-25  5:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Yang Li, Christophe JAILLET,
	linux-kernel

Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
uses "rtd3_work" and "idle_work" to manage it's own runtime PM state
machine.

When its child device, rtsx_pci_sdmmc, uses runtime PM refcount
correctly, all the additional works can be managed by generic runtime PM
helpers.

So consolidate "idle_work" and "rtd3_work" into generic runtime idle
callback and runtime suspend callback, respectively.

Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v6:
 - Change autosuspend delay to 10s as Realtek suggested.

v5:
v4:
 - No change.

v3:
 - Allow runtime PM for all devices, but only schedule runtime suspend
   for devices with rtd3_en flagged.

v2:
 - Remove unused idle_work and rtd3_work from rtsx_pcr.

 drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
 include/linux/rtsx_pci.h           |   3 -
 2 files changed, 39 insertions(+), 82 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 6ac509c1821c9..8aba47a7d9736 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
 	if (pcr->remove_pci)
 		return;
 
-	if (pcr->rtd3_en)
-		if (pcr->is_runtime_suspended) {
-			pm_runtime_get(&(pcr->pci->dev));
-			pcr->is_runtime_suspended = false;
-		}
-
 	if (pcr->state != PDEV_STAT_RUN) {
 		pcr->state = PDEV_STAT_RUN;
 		if (pcr->ops->enable_auto_blink)
 			pcr->ops->enable_auto_blink(pcr);
 		rtsx_pm_full_on(pcr);
 	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-	if (!pcr->is_runtime_suspended)
-		pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if (pcr->rtd3_en)
-		mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
 static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 {
 	/* Set relink_time to 0 */
@@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 	pcr->card_inserted = 0;
 	pcr->card_removed = 0;
 	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
 	pcr->msi_en = msi_en;
 	if (pcr->msi_en) {
@@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
 		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
 	}
 
-	if (pcr->rtd3_en) {
-		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-		pm_runtime_allow(&pcidev->dev);
-		pm_runtime_enable(&pcidev->dev);
-		pcr->is_runtime_suspended = false;
-	}
-
 
 	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
 			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
 	if (ret < 0)
 		goto free_slots;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+	pm_runtime_allow(&pcidev->dev);
+	pm_runtime_put(&pcidev->dev);
 
 	return 0;
 
@@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	struct pcr_handle *handle = pci_get_drvdata(pcidev);
 	struct rtsx_pcr *pcr = handle->pcr;
 
-	if (pcr->rtd3_en)
-		pm_runtime_get_noresume(&pcr->pci->dev);
-
 	pcr->remove_pci = true;
 
+	pm_runtime_get_sync(&pcidev->dev);
+	pm_runtime_forbid(&pcidev->dev);
+
 	/* Disable interrupts at the pcr level */
 	spin_lock_irq(&pcr->lock);
 	rtsx_pci_writel(pcr, RTSX_BIER, 0);
@@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	spin_unlock_irq(&pcr->lock);
 
 	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-	if (pcr->rtd3_en)
-		cancel_delayed_work_sync(&pcr->rtd3_work);
 
 	mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 	idr_remove(&rtsx_pci_idr, pcr->id);
 	spin_unlock(&rtsx_pci_lock);
 
-	if (pcr->rtd3_en) {
-		pm_runtime_disable(&pcr->pci->dev);
-		pm_runtime_put_noidle(&pcr->pci->dev);
-	}
-
 	kfree(pcr->slots);
 	kfree(pcr);
 	kfree(handle);
@@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 	pcr = handle->pcr;
 
 	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 	if (ret)
 		goto out;
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
 	mutex_unlock(&pcr->pcr_mutex);
 	return ret;
@@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 		pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+	struct pci_dev *pcidev = to_pci_dev(device);
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	dev_dbg(device, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	if (pcr->rtd3_en)
+		pm_schedule_suspend(device, 10000);
+
+	return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
@@ -1794,31 +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 
 	handle = pci_get_drvdata(pcidev);
 	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->rtd3_work);
-	cancel_delayed_work(&pcr->idle_work);
+	dev_dbg(device, "--> %s\n", __func__);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
-	pcr->is_runtime_suspended = true;
-
 	return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+	dev_dbg(device, "--> %s\n", __func__);
 
 	mutex_lock(&pcr->pcr_mutex);
 
@@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 				pcr->slots[RTSX_SD_CARD].p_dev);
 	}
 
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 4ab7bfc675f11..89b7d34e25b63 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1201,8 +1201,6 @@ struct rtsx_pcr {
 	unsigned int			card_exist;
 
 	struct delayed_work		carddet_work;
-	struct delayed_work		idle_work;
-	struct delayed_work		rtd3_work;
 
 	spinlock_t			lock;
 	struct mutex			pcr_mutex;
@@ -1212,7 +1210,6 @@ struct rtsx_pcr {
 	unsigned int			cur_clock;
 	bool				remove_pci;
 	bool				msi_en;
-	bool				is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50		(1 << 0)
 #define EXTRA_CAPS_SD_SDR104		(1 << 1)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v6 3/4] misc: rtsx: Cleanup power management ops
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-25  5:50       ` [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
@ 2022-01-25  5:50       ` Kai-Heng Feng
  2022-01-25  6:38         ` Ricky WU
  2022-01-25  5:50       ` [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
                         ` (2 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-25  5:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Christophe JAILLET, Yang Li,
	linux-kernel

- Use cancel_delayed_work_sync to ensure there's no race with
  carddet_work.

- Remove device_wakeup_disable to save some CPU cycles. If the device
  really has ACPI _DSW then the wakeup should be disabled in probe
  routine.

- Remove fetch_vendor_settings from runtime resume routine, since they
  are already saved in "struct rtsx_pcr".

- Move variable assignments to the top of the functions.

Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v6:
v5:
 - No change.

v4:
 - Move variable assignments to the top of the functions.

v3:
v2:
 - No change.

 drivers/misc/cardreader/rtsx_pcr.c | 34 ++++++++----------------------
 1 file changed, 9 insertions(+), 25 deletions(-)

diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 8aba47a7d9736..3c97d3b50456e 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1660,22 +1660,17 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 {
 	struct pci_dev *pcidev = to_pci_dev(dev_d);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
-	cancel_delayed_work(&pcr->carddet_work);
+	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
 
 	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
-	device_wakeup_disable(dev_d);
-
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
 }
@@ -1683,15 +1678,12 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 {
 	struct pci_dev *pcidev = to_pci_dev(dev_d);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 	int ret = 0;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
 	mutex_lock(&pcr->pcr_mutex);
 
 	ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
@@ -1711,13 +1703,11 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 
 static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 {
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
 	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
 
 	pci_disable_device(pcidev);
@@ -1756,11 +1746,8 @@ static int rtsx_pci_runtime_idle(struct device *device)
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
 	struct pci_dev *pcidev = to_pci_dev(device);
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
-
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
 
 	dev_dbg(device, "--> %s\n", __func__);
 
@@ -1786,9 +1773,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
 
-	if (pcr->ops->fetch_vendor_settings)
-		pcr->ops->fetch_vendor_settings(pcr);
-
 	rtsx_pci_init_hw(pcr);
 
 	if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) {
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
  2022-01-25  5:50       ` [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
  2022-01-25  5:50       ` [PATCH v6 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
@ 2022-01-25  5:50       ` Kai-Heng Feng
  2022-01-25  6:38         ` Ricky WU
  2022-01-25  6:37       ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Ricky WU
  2022-02-04 12:28       ` Ulf Hansson
  4 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-01-25  5:50 UTC (permalink / raw)
  To: arnd, gregkh, ulf.hansson
  Cc: linux-pm, Kai-Heng Feng, Ricky WU, Yang Li, Christophe JAILLET,
	linux-kernel

Set more registers in force_power_down callback to avoid S3 wakeup from
hotplugging cards.

This is originally written by Ricky WU.

Link: https://lore.kernel.org/lkml/c4525b4738f94483b9b8f8571fc80646@realtek.com/
Cc: Ricky WU <ricky_wu@realtek.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
v6:
v5:
v4:
v3:
v2:
 - No change.

 drivers/misc/cardreader/rtl8411.c  |  2 +-
 drivers/misc/cardreader/rts5209.c  |  2 +-
 drivers/misc/cardreader/rts5228.c  |  2 +-
 drivers/misc/cardreader/rts5229.c  |  2 +-
 drivers/misc/cardreader/rts5249.c  | 31 ++++++++++++++++++++++++++++--
 drivers/misc/cardreader/rts5261.c  |  2 +-
 drivers/misc/cardreader/rtsx_pcr.c | 14 +++++++-------
 drivers/misc/cardreader/rtsx_pcr.h |  1 +
 include/linux/rtsx_pci.h           |  2 +-
 9 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/cardreader/rtl8411.c b/drivers/misc/cardreader/rtl8411.c
index 4c5621b17a6fb..06457e875a90c 100644
--- a/drivers/misc/cardreader/rtl8411.c
+++ b/drivers/misc/cardreader/rtl8411.c
@@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c
index 29f5414072bf1..52b0a476ba51f 100644
--- a/drivers/misc/cardreader/rts5209.c
+++ b/drivers/misc/cardreader/rts5209.c
@@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	}
 }
 
-static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c
index ffc128278613b..ffe3afbf8bfed 100644
--- a/drivers/misc/cardreader/rts5228.c
+++ b/drivers/misc/cardreader/rts5228.c
@@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
 	return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
 }
 
-static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rts5229.c b/drivers/misc/cardreader/rts5229.c
index c748eaf1ec1f9..b0edd8006d52f 100644
--- a/drivers/misc/cardreader/rts5229.c
+++ b/drivers/misc/cardreader/rts5229.c
@@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
 		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
 }
diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c
index 53f3a1f45c4a7..91d240dd68faa 100644
--- a/drivers/misc/cardreader/rts5249.c
+++ b/drivers/misc/cardreader/rts5249.c
@@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
 	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
 
-	pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+		pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
 
 	if (rtsx_check_mmc_support(reg))
 		pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
@@ -143,6 +144,27 @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
 	return 0;
 }
 
+static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+	/* Set relink_time to 0 */
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+				RELINK_TIME_MASK, 0);
+
+	rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+	if (!runtime) {
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+				CD_RESUME_EN_MASK, 0);
+		rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00);
+		rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20);
+	}
+
+	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
 static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr)
 {
 	u8 cnt, sv;
@@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 
 	rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
 
-	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
 		rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN);
+		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+			CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+	}
 
 	if (pcr->rtd3_en) {
 		if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
@@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
 	.card_power_on = rtsx_base_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rtsx_base_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
@@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
 	.card_power_on = rts525a_card_power_on,
 	.card_power_off = rtsx_base_card_power_off,
 	.switch_output_voltage = rts525a_switch_output_voltage,
+	.force_power_down = rts52xa_force_power_down,
 	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 1fd4e0e507302..64333347c14a4 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
 	pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg);
 }
 
-static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index 3c97d3b50456e..1cb6425e83697 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -1086,7 +1086,7 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
 	rtsx_comm_pm_power_saving(pcr);
 }
 
-static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtsx_base_force_power_down(struct rtsx_pcr *pcr)
 {
 	/* Set relink_time to 0 */
 	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -1100,7 +1100,7 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
 }
 
-static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
 	if (pcr->ops->turn_off_led)
 		pcr->ops->turn_off_led(pcr);
@@ -1112,9 +1112,9 @@ static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
 	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
 
 	if (pcr->ops->force_power_down)
-		pcr->ops->force_power_down(pcr, pm_state);
+		pcr->ops->force_power_down(pcr, pm_state, runtime);
 	else
-		rtsx_base_force_power_down(pcr, pm_state);
+		rtsx_base_force_power_down(pcr);
 }
 
 void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
@@ -1669,7 +1669,7 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 
 	mutex_lock(&pcr->pcr_mutex);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, false);
 
 	mutex_unlock(&pcr->pcr_mutex);
 	return 0;
@@ -1708,7 +1708,7 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 
 	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S1, false);
 
 	pci_disable_device(pcidev);
 	free_irq(pcr->irq, (void *)pcr);
@@ -1754,7 +1754,7 @@ static int rtsx_pci_runtime_suspend(struct device *device)
 	cancel_delayed_work_sync(&pcr->carddet_work);
 
 	mutex_lock(&pcr->pcr_mutex);
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3, true);
 
 	mutex_unlock(&pcr->pcr_mutex);
 
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
index daf057c4eea62..aa0ebd6672277 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -25,6 +25,7 @@
 #define REG_EFUSE_POWEROFF		0x00
 #define RTS5250_CLK_CFG3		0xFF79
 #define RTS525A_CFG_MEM_PD		0xF0
+#define RTS524A_AUTOLOAD_CFG1		0xFF7C
 #define RTS524A_PM_CTRL3		0xFF7E
 #define RTS525A_BIOS_CFG		0xFF2D
 #define RTS525A_LOAD_BIOS_FLAG	0x01
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 89b7d34e25b63..3d780b44e678a 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -1095,7 +1095,7 @@ struct pcr_ops {
 	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
 	int		(*conv_clk_and_div_n)(int clk, int dir);
 	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
-	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
+	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime);
 	void		(*stop_cmd)(struct rtsx_pcr *pcr);
 
 	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* RE: [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
                         ` (2 preceding siblings ...)
  2022-01-25  5:50       ` [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
@ 2022-01-25  6:37       ` Ricky WU
  2022-02-04 12:28       ` Ulf Hansson
  4 siblings, 0 replies; 35+ messages in thread
From: Ricky WU @ 2022-01-25  6:37 UTC (permalink / raw)
  To: Kai-Heng Feng, arnd, gregkh, ulf.hansson
  Cc: linux-pm, Thomas Hebb, linux-mmc, linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Tuesday, January 25, 2022 1:50 PM
> To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> Ricky WU <ricky_wu@realtek.com>; Thomas Hebb <tommyhebb@gmail.com>;
> linux-mmc@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle
> runtime PM
> 
> Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't use
> pm_runtime_{get,put}() helpers when it should, so the RPM refcount keeps at
> zero, hence its parent driver, rtsx_pci, has to do lots of weird tricks to keep it
> from runtime suspending.
> 
> So use those helpers at right places to properly manage runtime PM.
> 
> Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> Cc: Ricky WU <ricky_wu@realtek.com>
Tested-by: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v6:
>  - Change the auto suspend delay to 200ms as Realtek suggested.
> 
> v5:
>  - Revert back to v3 as Realtek suggested.
> 
> v4:
>  - Decrease the autosuspend delay to 200ms for more power saving.
> 
> v3:
> v2:
>  - No change.
> 
>  drivers/mmc/host/rtsx_pci_sdmmc.c | 44 +++++++++++++++++++++++--------
>  1 file changed, 33 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c
> b/drivers/mmc/host/rtsx_pci_sdmmc.c
> index 58cfaffa3c2d8..2a3f14afe9f83 100644
> --- a/drivers/mmc/host/rtsx_pci_sdmmc.c
> +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
> @@ -806,6 +806,7 @@ static void sd_request(struct work_struct *work)
>  	struct mmc_request *mrq = host->mrq;
>  	struct mmc_command *cmd = mrq->cmd;
>  	struct mmc_data *data = mrq->data;
> +	struct device *dev = &host->pdev->dev;
> 
>  	unsigned int data_size = 0;
>  	int err;
> @@ -822,6 +823,7 @@ static void sd_request(struct work_struct *work)
>  	}
> 
>  	mutex_lock(&pcr->pcr_mutex);
> +	pm_runtime_get_sync(dev);
> 
>  	rtsx_pci_start_run(pcr);
> 
> @@ -858,6 +860,8 @@ static void sd_request(struct work_struct *work)
>  			data->bytes_xfered = data->blocks * data->blksz;
>  	}
> 
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
>  	mutex_unlock(&pcr->pcr_mutex);
> 
>  finish:
> @@ -1080,6 +1084,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)  {
>  	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
>  	struct rtsx_pcr *pcr = host->pcr;
> +	struct device *dev = &host->pdev->dev;
> 
>  	if (host->eject)
>  		return;
> @@ -1088,6 +1093,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)
>  		return;
> 
>  	mutex_lock(&pcr->pcr_mutex);
> +	pm_runtime_get_sync(dev);
> 
>  	rtsx_pci_start_run(pcr);
> 
> @@ -1121,6 +1127,8 @@ static void sdmmc_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)
>  	rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth,
>  			host->initial_mode, host->double_clk, host->vpclk);
> 
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
>  	mutex_unlock(&pcr->pcr_mutex);
>  }
> 
> @@ -1128,6 +1136,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
> {
>  	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
>  	struct rtsx_pcr *pcr = host->pcr;
> +	struct device *dev = &host->pdev->dev;
>  	int ro = 0;
>  	u32 val;
> 
> @@ -1135,6 +1144,7 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
>  		return -ENOMEDIUM;
> 
>  	mutex_lock(&pcr->pcr_mutex);
> +	pm_runtime_get_sync(dev);
> 
>  	rtsx_pci_start_run(pcr);
> 
> @@ -1144,6 +1154,8 @@ static int sdmmc_get_ro(struct mmc_host *mmc)
>  	if (val & SD_WRITE_PROTECT)
>  		ro = 1;
> 
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
>  	mutex_unlock(&pcr->pcr_mutex);
> 
>  	return ro;
> @@ -1153,6 +1165,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
> {
>  	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
>  	struct rtsx_pcr *pcr = host->pcr;
> +	struct device *dev = &host->pdev->dev;
>  	int cd = 0;
>  	u32 val;
> 
> @@ -1160,6 +1173,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
>  		return cd;
> 
>  	mutex_lock(&pcr->pcr_mutex);
> +	pm_runtime_get_sync(dev);
> 
>  	rtsx_pci_start_run(pcr);
> 
> @@ -1169,6 +1183,8 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
>  	if (val & SD_EXIST)
>  		cd = 1;
> 
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
>  	mutex_unlock(&pcr->pcr_mutex);
> 
>  	return cd;
> @@ -1251,6 +1267,7 @@ static int sdmmc_switch_voltage(struct mmc_host
> *mmc, struct mmc_ios *ios)  {
>  	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
>  	struct rtsx_pcr *pcr = host->pcr;
> +	struct device *dev = &host->pdev->dev;
>  	int err = 0;
>  	u8 voltage;
> 
> @@ -1265,6 +1282,7 @@ static int sdmmc_switch_voltage(struct mmc_host
> *mmc, struct mmc_ios *ios)
>  		return err;
> 
>  	mutex_lock(&pcr->pcr_mutex);
> +	pm_runtime_get_sync(dev);
> 
>  	rtsx_pci_start_run(pcr);
> 
> @@ -1294,6 +1312,8 @@ static int sdmmc_switch_voltage(struct mmc_host
> *mmc, struct mmc_ios *ios)
>  	err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
>  			SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
> 
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
>  	mutex_unlock(&pcr->pcr_mutex);
> 
>  	return err;
> @@ -1303,6 +1323,7 @@ static int sdmmc_execute_tuning(struct mmc_host
> *mmc, u32 opcode)  {
>  	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
>  	struct rtsx_pcr *pcr = host->pcr;
> +	struct device *dev = &host->pdev->dev;
>  	int err = 0;
> 
>  	if (host->eject)
> @@ -1313,6 +1334,7 @@ static int sdmmc_execute_tuning(struct mmc_host
> *mmc, u32 opcode)
>  		return err;
> 
>  	mutex_lock(&pcr->pcr_mutex);
> +	pm_runtime_get_sync(dev);
> 
>  	rtsx_pci_start_run(pcr);
> 
> @@ -1345,6 +1367,8 @@ static int sdmmc_execute_tuning(struct mmc_host
> *mmc, u32 opcode)
>  		err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true);
> 
>  out:
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
>  	mutex_unlock(&pcr->pcr_mutex);
> 
>  	return err;
> @@ -1495,12 +1519,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct
> platform_device *pdev)
> 
>  	realtek_init_host(host);
> 
> -	if (pcr->rtd3_en) {
> -		pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
> -		pm_runtime_use_autosuspend(&pdev->dev);
> -		pm_runtime_enable(&pdev->dev);
> -	}
> -
> +	pm_runtime_no_callbacks(&pdev->dev);
> +	pm_runtime_set_active(&pdev->dev);
> +	pm_runtime_enable(&pdev->dev);
> +	pm_runtime_set_autosuspend_delay(&pdev->dev, 200);
> +	pm_runtime_mark_last_busy(&pdev->dev);
> +	pm_runtime_use_autosuspend(&pdev->dev);
> 
>  	mmc_add_host(mmc);
> 
> @@ -1521,11 +1545,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct
> platform_device *pdev)
>  	pcr->slots[RTSX_SD_CARD].card_event = NULL;
>  	mmc = host->mmc;
> 
> -	if (pcr->rtd3_en) {
> -		pm_runtime_dont_use_autosuspend(&pdev->dev);
> -		pm_runtime_disable(&pdev->dev);
> -	}
> -
>  	cancel_work_sync(&host->work);
> 
>  	mutex_lock(&host->host_mutex);
> @@ -1548,6 +1567,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct
> platform_device *pdev)
> 
>  	flush_work(&host->work);
> 
> +	pm_runtime_dont_use_autosuspend(&pdev->dev);
> +	pm_runtime_disable(&pdev->dev);
> +
>  	mmc_free_host(mmc);
> 
>  	dev_dbg(&(pdev->dev),
> --
> 2.33.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow
  2022-01-25  5:50       ` [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
@ 2022-01-25  6:38         ` Ricky WU
  0 siblings, 0 replies; 35+ messages in thread
From: Ricky WU @ 2022-01-25  6:38 UTC (permalink / raw)
  To: Kai-Heng Feng, arnd, gregkh, ulf.hansson
  Cc: linux-pm, Yang Li, Christophe JAILLET, linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Tuesday, January 25, 2022 1:50 PM
> To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> Ricky WU <ricky_wu@realtek.com>; Yang Li <yang.lee@linux.alibaba.com>;
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>;
> linux-kernel@vger.kernel.org
> Subject: [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow
> 
> Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses
> "rtd3_work" and "idle_work" to manage it's own runtime PM state machine.
> 
> When its child device, rtsx_pci_sdmmc, uses runtime PM refcount correctly, all
> the additional works can be managed by generic runtime PM helpers.
> 
> So consolidate "idle_work" and "rtd3_work" into generic runtime idle callback
> and runtime suspend callback, respectively.
> 
> Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> Cc: Ricky WU <ricky_wu@realtek.com>
Tested-by: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v6:
>  - Change autosuspend delay to 10s as Realtek suggested.
> 
> v5:
> v4:
>  - No change.
> 
> v3:
>  - Allow runtime PM for all devices, but only schedule runtime suspend
>    for devices with rtd3_en flagged.
> 
> v2:
>  - Remove unused idle_work and rtd3_work from rtsx_pcr.
> 
>  drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++-------------------
>  include/linux/rtsx_pci.h           |   3 -
>  2 files changed, 39 insertions(+), 82 deletions(-)
> 
> diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> b/drivers/misc/cardreader/rtsx_pcr.c
> index 6ac509c1821c9..8aba47a7d9736 100644
> --- a/drivers/misc/cardreader/rtsx_pcr.c
> +++ b/drivers/misc/cardreader/rtsx_pcr.c
> @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
>  	if (pcr->remove_pci)
>  		return;
> 
> -	if (pcr->rtd3_en)
> -		if (pcr->is_runtime_suspended) {
> -			pm_runtime_get(&(pcr->pci->dev));
> -			pcr->is_runtime_suspended = false;
> -		}
> -
>  	if (pcr->state != PDEV_STAT_RUN) {
>  		pcr->state = PDEV_STAT_RUN;
>  		if (pcr->ops->enable_auto_blink)
>  			pcr->ops->enable_auto_blink(pcr);
>  		rtsx_pm_full_on(pcr);
>  	}
> -
> -	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
>  }
>  EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
> 
> @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr
> *pcr)
>  	rtsx_comm_pm_power_saving(pcr);
>  }
> 
> -static void rtsx_pci_rtd3_work(struct work_struct *work) -{
> -	struct delayed_work *dwork = to_delayed_work(work);
> -	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
> -
> -	pcr_dbg(pcr, "--> %s\n", __func__);
> -	if (!pcr->is_runtime_suspended)
> -		pm_runtime_put(&(pcr->pci->dev));
> -}
> -
> -static void rtsx_pci_idle_work(struct work_struct *work) -{
> -	struct delayed_work *dwork = to_delayed_work(work);
> -	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
> -
> -	pcr_dbg(pcr, "--> %s\n", __func__);
> -
> -	mutex_lock(&pcr->pcr_mutex);
> -
> -	pcr->state = PDEV_STAT_IDLE;
> -
> -	if (pcr->ops->disable_auto_blink)
> -		pcr->ops->disable_auto_blink(pcr);
> -	if (pcr->ops->turn_off_led)
> -		pcr->ops->turn_off_led(pcr);
> -
> -	rtsx_pm_power_saving(pcr);
> -
> -	mutex_unlock(&pcr->pcr_mutex);
> -
> -	if (pcr->rtd3_en)
> -		mod_delayed_work(system_wq, &pcr->rtd3_work,
> msecs_to_jiffies(10000));
> -}
> -
>  static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> {
>  	/* Set relink_time to 0 */
> @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
>  	pcr->card_inserted = 0;
>  	pcr->card_removed = 0;
>  	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
> -	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
> 
>  	pcr->msi_en = msi_en;
>  	if (pcr->msi_en) {
> @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
>  		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
>  	}
> 
> -	if (pcr->rtd3_en) {
> -		INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
> -		pm_runtime_allow(&pcidev->dev);
> -		pm_runtime_enable(&pcidev->dev);
> -		pcr->is_runtime_suspended = false;
> -	}
> -
> 
>  	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
>  			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
>  	if (ret < 0)
>  		goto free_slots;
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> +	pm_runtime_allow(&pcidev->dev);
> +	pm_runtime_put(&pcidev->dev);
> 
>  	return 0;
> 
> @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
>  	struct pcr_handle *handle = pci_get_drvdata(pcidev);
>  	struct rtsx_pcr *pcr = handle->pcr;
> 
> -	if (pcr->rtd3_en)
> -		pm_runtime_get_noresume(&pcr->pci->dev);
> -
>  	pcr->remove_pci = true;
> 
> +	pm_runtime_get_sync(&pcidev->dev);
> +	pm_runtime_forbid(&pcidev->dev);
> +
>  	/* Disable interrupts at the pcr level */
>  	spin_lock_irq(&pcr->lock);
>  	rtsx_pci_writel(pcr, RTSX_BIER, 0);
> @@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
>  	spin_unlock_irq(&pcr->lock);
> 
>  	cancel_delayed_work_sync(&pcr->carddet_work);
> -	cancel_delayed_work_sync(&pcr->idle_work);
> -	if (pcr->rtd3_en)
> -		cancel_delayed_work_sync(&pcr->rtd3_work);
> 
>  	mfd_remove_devices(&pcidev->dev);
> 
> @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)
>  	idr_remove(&rtsx_pci_idr, pcr->id);
>  	spin_unlock(&rtsx_pci_lock);
> 
> -	if (pcr->rtd3_en) {
> -		pm_runtime_disable(&pcr->pci->dev);
> -		pm_runtime_put_noidle(&pcr->pci->dev);
> -	}
> -
>  	kfree(pcr->slots);
>  	kfree(pcr);
>  	kfree(handle);
> @@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct
> device *dev_d)
>  	pcr = handle->pcr;
> 
>  	cancel_delayed_work(&pcr->carddet_work);
> -	cancel_delayed_work(&pcr->idle_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> @@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct
> device *dev_d)
>  	if (ret)
>  		goto out;
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> -
>  out:
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return ret;
> @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev
> *pcidev)
>  		pci_disable_msi(pcr->pci);
>  }
> 
> +static int rtsx_pci_runtime_idle(struct device *device) {
> +	struct pci_dev *pcidev = to_pci_dev(device);
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> +
> +	dev_dbg(device, "--> %s\n", __func__);
> +
> +	mutex_lock(&pcr->pcr_mutex);
> +
> +	pcr->state = PDEV_STAT_IDLE;
> +
> +	if (pcr->ops->disable_auto_blink)
> +		pcr->ops->disable_auto_blink(pcr);
> +	if (pcr->ops->turn_off_led)
> +		pcr->ops->turn_off_led(pcr);
> +
> +	rtsx_pm_power_saving(pcr);
> +
> +	mutex_unlock(&pcr->pcr_mutex);
> +
> +	if (pcr->rtd3_en)
> +		pm_schedule_suspend(device, 10000);
> +
> +	return -EBUSY;
> +}
> +
>  static int rtsx_pci_runtime_suspend(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31 +1761,26 @@
> static int rtsx_pci_runtime_suspend(struct device *device)
> 
>  	handle = pci_get_drvdata(pcidev);
>  	pcr = handle->pcr;
> -	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	cancel_delayed_work(&pcr->carddet_work);
> -	cancel_delayed_work(&pcr->rtd3_work);
> -	cancel_delayed_work(&pcr->idle_work);
> +	dev_dbg(device, "--> %s\n", __func__);
> +
> +	cancel_delayed_work_sync(&pcr->carddet_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
>  	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> 
>  	mutex_unlock(&pcr->pcr_mutex);
> 
> -	pcr->is_runtime_suspended = true;
> -
>  	return 0;
>  }
> 
>  static int rtsx_pci_runtime_resume(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device);
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> 
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
> -	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> +	dev_dbg(device, "--> %s\n", __func__);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
>  				pcr->slots[RTSX_SD_CARD].p_dev);
>  	}
> 
> -	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
> -
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return 0;
>  }
> @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
> 
>  static const struct dev_pm_ops rtsx_pci_pm_ops = {
>  	SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
> -	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> rtsx_pci_runtime_resume, NULL)
> +	SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend,
> rtsx_pci_runtime_resume,
> +rtsx_pci_runtime_idle)
>  };
> 
>  static struct pci_driver rtsx_pci_driver = { diff --git a/include/linux/rtsx_pci.h
> b/include/linux/rtsx_pci.h index 4ab7bfc675f11..89b7d34e25b63 100644
> --- a/include/linux/rtsx_pci.h
> +++ b/include/linux/rtsx_pci.h
> @@ -1201,8 +1201,6 @@ struct rtsx_pcr {
>  	unsigned int			card_exist;
> 
>  	struct delayed_work		carddet_work;
> -	struct delayed_work		idle_work;
> -	struct delayed_work		rtd3_work;
> 
>  	spinlock_t			lock;
>  	struct mutex			pcr_mutex;
> @@ -1212,7 +1210,6 @@ struct rtsx_pcr {
>  	unsigned int			cur_clock;
>  	bool				remove_pci;
>  	bool				msi_en;
> -	bool				is_runtime_suspended;
> 
>  #define EXTRA_CAPS_SD_SDR50		(1 << 0)
>  #define EXTRA_CAPS_SD_SDR104		(1 << 1)
> --
> 2.33.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH v6 3/4] misc: rtsx: Cleanup power management ops
  2022-01-25  5:50       ` [PATCH v6 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
@ 2022-01-25  6:38         ` Ricky WU
  0 siblings, 0 replies; 35+ messages in thread
From: Ricky WU @ 2022-01-25  6:38 UTC (permalink / raw)
  To: Kai-Heng Feng, arnd, gregkh, ulf.hansson
  Cc: linux-pm, Christophe JAILLET, Yang Li, linux-kernel



> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Tuesday, January 25, 2022 1:50 PM
> To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> Ricky WU <ricky_wu@realtek.com>; Christophe JAILLET
> <christophe.jaillet@wanadoo.fr>; Yang Li <yang.lee@linux.alibaba.com>;
> linux-kernel@vger.kernel.org
> Subject: [PATCH v6 3/4] misc: rtsx: Cleanup power management ops
> 
> - Use cancel_delayed_work_sync to ensure there's no race with
>   carddet_work.
> 
> - Remove device_wakeup_disable to save some CPU cycles. If the device
>   really has ACPI _DSW then the wakeup should be disabled in probe
>   routine.
> 
> - Remove fetch_vendor_settings from runtime resume routine, since they
>   are already saved in "struct rtsx_pcr".
> 
> - Move variable assignments to the top of the functions.
> 
> Cc: Ricky WU <ricky_wu@realtek.com>
Tested-by: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v6:
> v5:
>  - No change.
> 
> v4:
>  - Move variable assignments to the top of the functions.
> 
> v3:
> v2:
>  - No change.
> 
>  drivers/misc/cardreader/rtsx_pcr.c | 34 ++++++++----------------------
>  1 file changed, 9 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> b/drivers/misc/cardreader/rtsx_pcr.c
> index 8aba47a7d9736..3c97d3b50456e 100644
> --- a/drivers/misc/cardreader/rtsx_pcr.c
> +++ b/drivers/misc/cardreader/rtsx_pcr.c
> @@ -1660,22 +1660,17 @@ static void rtsx_pci_remove(struct pci_dev
> *pcidev)  static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
> {
>  	struct pci_dev *pcidev = to_pci_dev(dev_d);
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> 
>  	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
> -
> -	cancel_delayed_work(&pcr->carddet_work);
> +	cancel_delayed_work_sync(&pcr->carddet_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
>  	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> 
> -	device_wakeup_disable(dev_d);
> -
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return 0;
>  }
> @@ -1683,15 +1678,12 @@ static int __maybe_unused
> rtsx_pci_suspend(struct device *dev_d)  static int __maybe_unused
> rtsx_pci_resume(struct device *dev_d)  {
>  	struct pci_dev *pcidev = to_pci_dev(dev_d);
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
>  	int ret = 0;
> 
>  	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
> -
>  	mutex_lock(&pcr->pcr_mutex);
> 
>  	ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); @@
> -1711,13 +1703,11 @@ static int __maybe_unused rtsx_pci_resume(struct
> device *dev_d)
> 
>  static void rtsx_pci_shutdown(struct pci_dev *pcidev)  {
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> 
>  	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
>  	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
> 
>  	pci_disable_device(pcidev);
> @@ -1756,11 +1746,8 @@ static int rtsx_pci_runtime_idle(struct device
> *device)  static int rtsx_pci_runtime_suspend(struct device *device)  {
>  	struct pci_dev *pcidev = to_pci_dev(device);
> -	struct pcr_handle *handle;
> -	struct rtsx_pcr *pcr;
> -
> -	handle = pci_get_drvdata(pcidev);
> -	pcr = handle->pcr;
> +	struct pcr_handle *handle = pci_get_drvdata(pcidev);
> +	struct rtsx_pcr *pcr = handle->pcr;
> 
>  	dev_dbg(device, "--> %s\n", __func__);
> 
> @@ -1786,9 +1773,6 @@ static int rtsx_pci_runtime_resume(struct device
> *device)
> 
>  	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
> 
> -	if (pcr->ops->fetch_vendor_settings)
> -		pcr->ops->fetch_vendor_settings(pcr);
> -
>  	rtsx_pci_init_hw(pcr);
> 
>  	if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) {
> --
> 2.33.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend
  2022-01-25  5:50       ` [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
@ 2022-01-25  6:38         ` Ricky WU
  0 siblings, 0 replies; 35+ messages in thread
From: Ricky WU @ 2022-01-25  6:38 UTC (permalink / raw)
  To: Kai-Heng Feng, arnd, gregkh, ulf.hansson
  Cc: linux-pm, Yang Li, Christophe JAILLET, linux-kernel

> -----Original Message-----
> From: Kai-Heng Feng <kai.heng.feng@canonical.com>
> Sent: Tuesday, January 25, 2022 1:50 PM
> To: arnd@arndb.de; gregkh@linuxfoundation.org; ulf.hansson@linaro.org
> Cc: linux-pm@vger.kernel.org; Kai-Heng Feng <kai.heng.feng@canonical.com>;
> Ricky WU <ricky_wu@realtek.com>; Yang Li <yang.lee@linux.alibaba.com>;
> Christophe JAILLET <christophe.jaillet@wanadoo.fr>;
> linux-kernel@vger.kernel.org
> Subject: [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend
> 
> Set more registers in force_power_down callback to avoid S3 wakeup from
> hotplugging cards.
> 
> This is originally written by Ricky WU.
> 
> Link:
> https://lore.kernel.org/lkml/c4525b4738f94483b9b8f8571fc80646@realtek.co
> m/
> Cc: Ricky WU <ricky_wu@realtek.com>
Tested-by: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
> v6:
> v5:
> v4:
> v3:
> v2:
>  - No change.
> 
>  drivers/misc/cardreader/rtl8411.c  |  2 +-
> drivers/misc/cardreader/rts5209.c  |  2 +-
> drivers/misc/cardreader/rts5228.c  |  2 +-
> drivers/misc/cardreader/rts5229.c  |  2 +-
> drivers/misc/cardreader/rts5249.c  | 31 ++++++++++++++++++++++++++++--
> drivers/misc/cardreader/rts5261.c  |  2 +-
> drivers/misc/cardreader/rtsx_pcr.c | 14 +++++++-------
> drivers/misc/cardreader/rtsx_pcr.h |  1 +
>  include/linux/rtsx_pci.h           |  2 +-
>  9 files changed, 43 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/misc/cardreader/rtl8411.c
> b/drivers/misc/cardreader/rtl8411.c
> index 4c5621b17a6fb..06457e875a90c 100644
> --- a/drivers/misc/cardreader/rtl8411.c
> +++ b/drivers/misc/cardreader/rtl8411.c
> @@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct
> rtsx_pcr *pcr)
>  		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
>  }
> 
> -static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> +static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state,
> +bool runtime)
>  {
>  	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);  } diff --git
> a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c
> index 29f5414072bf1..52b0a476ba51f 100644
> --- a/drivers/misc/cardreader/rts5209.c
> +++ b/drivers/misc/cardreader/rts5209.c
> @@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr
> *pcr)
>  	}
>  }
> 
> -static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> +static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state,
> +bool runtime)
>  {
>  	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);  } diff --git
> a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c
> index ffc128278613b..ffe3afbf8bfed 100644
> --- a/drivers/misc/cardreader/rts5228.c
> +++ b/drivers/misc/cardreader/rts5228.c
> @@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
>  	return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);  }
> 
> -static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> +static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state,
> +bool runtime)
>  {
>  	/* Set relink_time to 0 */
>  	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF,
> 0); diff --git a/drivers/misc/cardreader/rts5229.c
> b/drivers/misc/cardreader/rts5229.c
> index c748eaf1ec1f9..b0edd8006d52f 100644
> --- a/drivers/misc/cardreader/rts5229.c
> +++ b/drivers/misc/cardreader/rts5229.c
> @@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr
> *pcr)
>  		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
>  }
> 
> -static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> +static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state,
> +bool runtime)
>  {
>  	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);  } diff --git
> a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c
> index 53f3a1f45c4a7..91d240dd68faa 100644
> --- a/drivers/misc/cardreader/rts5249.c
> +++ b/drivers/misc/cardreader/rts5249.c
> @@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct
> rtsx_pcr *pcr)
>  	pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
>  	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
> 
> -	pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
> +	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
> +		pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
> 
>  	if (rtsx_check_mmc_support(reg))
>  		pcr->extra_caps |= EXTRA_CAPS_NO_MMC; @@ -143,6 +144,27
> @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
>  	return 0;
>  }
> 
> +static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state,
> +bool runtime) {
> +	/* Set relink_time to 0 */
> +	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF,
> 0);
> +	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF,
> 0);
> +	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
> +				RELINK_TIME_MASK, 0);
> +
> +	rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
> +			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
> +
> +	if (!runtime) {
> +		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
> +				CD_RESUME_EN_MASK, 0);
> +		rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00);
> +		rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20);
> +	}
> +
> +	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN,
> ALL_POWER_DOWN);
> +}
> +
>  static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr)  {
>  	u8 cnt, sv;
> @@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
> 
>  	rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
> 
> -	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
> +	if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
>  		rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN,
> PWD_SUSPND_EN);
> +		rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
> +			CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
> +	}
> 
>  	if (pcr->rtd3_en) {
>  		if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
> { @@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
>  	.card_power_on = rtsx_base_card_power_on,
>  	.card_power_off = rtsx_base_card_power_off,
>  	.switch_output_voltage = rtsx_base_switch_output_voltage,
> +	.force_power_down = rts52xa_force_power_down,
>  	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,  };
> 
> @@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
>  	.card_power_on = rts525a_card_power_on,
>  	.card_power_off = rtsx_base_card_power_off,
>  	.switch_output_voltage = rts525a_switch_output_voltage,
> +	.force_power_down = rts52xa_force_power_down,
>  	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,  };
> 
> diff --git a/drivers/misc/cardreader/rts5261.c
> b/drivers/misc/cardreader/rts5261.c
> index 1fd4e0e507302..64333347c14a4 100644
> --- a/drivers/misc/cardreader/rts5261.c
> +++ b/drivers/misc/cardreader/rts5261.c
> @@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct
> rtsx_pcr *pcr)
>  	pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg);
>  }
> 
> -static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> +static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state,
> +bool runtime)
>  {
>  	/* Set relink_time to 0 */
>  	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF,
> 0); diff --git a/drivers/misc/cardreader/rtsx_pcr.c
> b/drivers/misc/cardreader/rtsx_pcr.c
> index 3c97d3b50456e..1cb6425e83697 100644
> --- a/drivers/misc/cardreader/rtsx_pcr.c
> +++ b/drivers/misc/cardreader/rtsx_pcr.c
> @@ -1086,7 +1086,7 @@ static void rtsx_pm_power_saving(struct rtsx_pcr
> *pcr)
>  	rtsx_comm_pm_power_saving(pcr);
>  }
> 
> -static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
> +static void rtsx_base_force_power_down(struct rtsx_pcr *pcr)
>  {
>  	/* Set relink_time to 0 */
>  	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF,
> 0); @@ -1100,7 +1100,7 @@ static void rtsx_base_force_power_down(struct
> rtsx_pcr *pcr, u8 pm_state)
>  	rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN,
> ALL_POWER_DOWN);  }
> 
> -static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8
> pm_state)
> +static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8
> +pm_state, bool runtime)
>  {
>  	if (pcr->ops->turn_off_led)
>  		pcr->ops->turn_off_led(pcr);
> @@ -1112,9 +1112,9 @@ static void __maybe_unused
> rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
>  	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
> 
>  	if (pcr->ops->force_power_down)
> -		pcr->ops->force_power_down(pcr, pm_state);
> +		pcr->ops->force_power_down(pcr, pm_state, runtime);
>  	else
> -		rtsx_base_force_power_down(pcr, pm_state);
> +		rtsx_base_force_power_down(pcr);
>  }
> 
>  void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr) @@ -1669,7 +1669,7 @@
> static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
> 
>  	mutex_lock(&pcr->pcr_mutex);
> 
> -	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> +	rtsx_pci_power_off(pcr, HOST_ENTER_S3, false);
> 
>  	mutex_unlock(&pcr->pcr_mutex);
>  	return 0;
> @@ -1708,7 +1708,7 @@ static void rtsx_pci_shutdown(struct pci_dev
> *pcidev)
> 
>  	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
> 
> -	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
> +	rtsx_pci_power_off(pcr, HOST_ENTER_S1, false);
> 
>  	pci_disable_device(pcidev);
>  	free_irq(pcr->irq, (void *)pcr);
> @@ -1754,7 +1754,7 @@ static int rtsx_pci_runtime_suspend(struct device
> *device)
>  	cancel_delayed_work_sync(&pcr->carddet_work);
> 
>  	mutex_lock(&pcr->pcr_mutex);
> -	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
> +	rtsx_pci_power_off(pcr, HOST_ENTER_S3, true);
> 
>  	mutex_unlock(&pcr->pcr_mutex);
> 
> diff --git a/drivers/misc/cardreader/rtsx_pcr.h
> b/drivers/misc/cardreader/rtsx_pcr.h
> index daf057c4eea62..aa0ebd6672277 100644
> --- a/drivers/misc/cardreader/rtsx_pcr.h
> +++ b/drivers/misc/cardreader/rtsx_pcr.h
> @@ -25,6 +25,7 @@
>  #define REG_EFUSE_POWEROFF		0x00
>  #define RTS5250_CLK_CFG3		0xFF79
>  #define RTS525A_CFG_MEM_PD		0xF0
> +#define RTS524A_AUTOLOAD_CFG1		0xFF7C
>  #define RTS524A_PM_CTRL3		0xFF7E
>  #define RTS525A_BIOS_CFG		0xFF2D
>  #define RTS525A_LOAD_BIOS_FLAG	0x01
> diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index
> 89b7d34e25b63..3d780b44e678a 100644
> --- a/include/linux/rtsx_pci.h
> +++ b/include/linux/rtsx_pci.h
> @@ -1095,7 +1095,7 @@ struct pcr_ops {
>  	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
>  	int		(*conv_clk_and_div_n)(int clk, int dir);
>  	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
> -	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
> +	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool
> runtime);
>  	void		(*stop_cmd)(struct rtsx_pcr *pcr);
> 
>  	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
> --
> 2.33.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
                         ` (3 preceding siblings ...)
  2022-01-25  6:37       ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Ricky WU
@ 2022-02-04 12:28       ` Ulf Hansson
  2022-02-16  4:21         ` Kai-Heng Feng
  4 siblings, 1 reply; 35+ messages in thread
From: Ulf Hansson @ 2022-02-04 12:28 UTC (permalink / raw)
  To: Kai-Heng Feng
  Cc: arnd, gregkh, linux-pm, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

On Tue, 25 Jan 2022 at 06:50, Kai-Heng Feng <kai.heng.feng@canonical.com> wrote:
>
> Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
> use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
> keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
> weird tricks to keep it from runtime suspending.
>
> So use those helpers at right places to properly manage runtime PM.
>
> Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> Cc: Ricky WU <ricky_wu@realtek.com>
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>

The runtime PM reference counting for the mmc host device is managed
by the mmc core. Have a look at __mmc_claim_host() and
mmc_release_host().

In other words, the runtime PM reference counting should not be needed
in the mmc host driver, unless there are some specific cases, like for
example during ->probe|remove().

So perhaps it's only the changes in the ->probe|remove() functions
that you need to fix the problems? No?

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-02-04 12:28       ` Ulf Hansson
@ 2022-02-16  4:21         ` Kai-Heng Feng
  2022-02-16 10:22           ` Ulf Hansson
  0 siblings, 1 reply; 35+ messages in thread
From: Kai-Heng Feng @ 2022-02-16  4:21 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: arnd, gregkh, linux-pm, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

On Fri, Feb 4, 2022 at 8:28 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> On Tue, 25 Jan 2022 at 06:50, Kai-Heng Feng <kai.heng.feng@canonical.com> wrote:
> >
> > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
> > use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
> > keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
> > weird tricks to keep it from runtime suspending.
> >
> > So use those helpers at right places to properly manage runtime PM.
> >
> > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > Cc: Ricky WU <ricky_wu@realtek.com>
> > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
>
> The runtime PM reference counting for the mmc host device is managed
> by the mmc core. Have a look at __mmc_claim_host() and
> mmc_release_host().
>
> In other words, the runtime PM reference counting should not be needed
> in the mmc host driver, unless there are some specific cases, like for
> example during ->probe|remove().
>
> So perhaps it's only the changes in the ->probe|remove() functions
> that you need to fix the problems? No?

Yes you are right. Let me send a patch to remove redundant PM helpers
from this patch.

Kai-Heng

>
> [...]
>
> Kind regards
> Uffe

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM
  2022-02-16  4:21         ` Kai-Heng Feng
@ 2022-02-16 10:22           ` Ulf Hansson
  0 siblings, 0 replies; 35+ messages in thread
From: Ulf Hansson @ 2022-02-16 10:22 UTC (permalink / raw)
  To: Kai-Heng Feng
  Cc: arnd, gregkh, linux-pm, Ricky WU, Thomas Hebb, linux-mmc, linux-kernel

On Wed, 16 Feb 2022 at 05:21, Kai-Heng Feng <kai.heng.feng@canonical.com> wrote:
>
> On Fri, Feb 4, 2022 at 8:28 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
> >
> > On Tue, 25 Jan 2022 at 06:50, Kai-Heng Feng <kai.heng.feng@canonical.com> wrote:
> > >
> > > Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") doesn't
> > > use pm_runtime_{get,put}() helpers when it should, so the RPM refcount
> > > keeps at zero, hence its parent driver, rtsx_pci, has to do lots of
> > > weird tricks to keep it from runtime suspending.
> > >
> > > So use those helpers at right places to properly manage runtime PM.
> > >
> > > Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM")
> > > Cc: Ricky WU <ricky_wu@realtek.com>
> > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> >
> > The runtime PM reference counting for the mmc host device is managed
> > by the mmc core. Have a look at __mmc_claim_host() and
> > mmc_release_host().
> >
> > In other words, the runtime PM reference counting should not be needed
> > in the mmc host driver, unless there are some specific cases, like for
> > example during ->probe|remove().
> >
> > So perhaps it's only the changes in the ->probe|remove() functions
> > that you need to fix the problems? No?
>
> Yes you are right. Let me send a patch to remove redundant PM helpers
> from this patch.

Ohh, I didn't know that Greg already queued this up. Seems like I
don't get more than one week to review. :-)

Alright, I will look at your new patch then.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2022-02-16 10:23 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-20 14:50 [PATCH 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
2022-01-20 14:50 ` [PATCH 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
2022-01-21  1:40   ` [PATCH v2 " Kai-Heng Feng
2022-01-21  3:57     ` Ricky WU
2022-01-21  4:08       ` Kai-Heng Feng
2022-01-21  4:15         ` Ricky WU
2022-01-21  4:17           ` Kai-Heng Feng
2022-01-21  6:31     ` [PATCH v3 " Kai-Heng Feng
2022-01-21  9:58       ` Ricky WU
2022-01-21 12:39         ` Kai-Heng Feng
2022-01-24  3:26           ` Ricky WU
2022-01-24  4:53             ` Kai-Heng Feng
2022-01-24  5:10               ` Ricky WU
2022-01-24  5:26                 ` Kai-Heng Feng
2022-01-24  5:47     ` [PATCH v4 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
2022-01-24  5:47       ` [PATCH v4 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
2022-01-24  5:47       ` [PATCH v4 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
2022-01-24  5:47       ` [PATCH v4 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
2022-01-24  7:28     ` [PATCH v5 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
2022-01-24  7:28       ` [PATCH v5 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
2022-01-24  7:28       ` [PATCH v5 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
2022-01-24  7:28       ` [PATCH v5 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
2022-01-25  5:50     ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Kai-Heng Feng
2022-01-25  5:50       ` [PATCH v6 2/4] misc: rtsx: Rework runtime power management flow Kai-Heng Feng
2022-01-25  6:38         ` Ricky WU
2022-01-25  5:50       ` [PATCH v6 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
2022-01-25  6:38         ` Ricky WU
2022-01-25  5:50       ` [PATCH v6 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng
2022-01-25  6:38         ` Ricky WU
2022-01-25  6:37       ` [PATCH v6 1/4] mmc: rtsx: Use pm_runtime_{get,put}() to handle runtime PM Ricky WU
2022-02-04 12:28       ` Ulf Hansson
2022-02-16  4:21         ` Kai-Heng Feng
2022-02-16 10:22           ` Ulf Hansson
2022-01-20 14:50 ` [PATCH 3/4] misc: rtsx: Cleanup power management ops Kai-Heng Feng
2022-01-20 14:50 ` [PATCH 4/4] misc: rtsx: Quiesce rts5249 on system suspend Kai-Heng Feng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.