Skip to content

Commit 6269473

Browse files
Sujit Reddy ThummaJames Bottomley
authored andcommitted
[SCSI] ufs: Add runtime PM support for UFS host controller driver
Add runtime PM helpers to suspend/resume UFS controller at runtime. Enable runtime PM by default for pci and platform drivers as the initialized hardware can suspend if it is not used after bootup. Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org> Signed-off-by: Santosh Y <santoshsy@gmail.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
1 parent 66ec6d5 commit 6269473

File tree

3 files changed

+113
-7
lines changed

3 files changed

+113
-7
lines changed

drivers/scsi/ufs/ufshcd-pci.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "ufshcd.h"
3737
#include <linux/pci.h>
38+
#include <linux/pm_runtime.h>
3839

3940
#ifdef CONFIG_PM
4041
/**
@@ -44,7 +45,7 @@
4445
*
4546
* Returns -ENOSYS
4647
*/
47-
static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
48+
static int ufshcd_pci_suspend(struct device *dev)
4849
{
4950
/*
5051
* TODO:
@@ -61,7 +62,7 @@ static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
6162
*
6263
* Returns -ENOSYS
6364
*/
64-
static int ufshcd_pci_resume(struct pci_dev *pdev)
65+
static int ufshcd_pci_resume(struct device *dev)
6566
{
6667
/*
6768
* TODO:
@@ -71,8 +72,45 @@ static int ufshcd_pci_resume(struct pci_dev *pdev)
7172

7273
return -ENOSYS;
7374
}
75+
#else
76+
#define ufshcd_pci_suspend NULL
77+
#define ufshcd_pci_resume NULL
7478
#endif /* CONFIG_PM */
7579

80+
#ifdef CONFIG_PM_RUNTIME
81+
static int ufshcd_pci_runtime_suspend(struct device *dev)
82+
{
83+
struct ufs_hba *hba = dev_get_drvdata(dev);
84+
85+
if (!hba)
86+
return 0;
87+
88+
return ufshcd_runtime_suspend(hba);
89+
}
90+
static int ufshcd_pci_runtime_resume(struct device *dev)
91+
{
92+
struct ufs_hba *hba = dev_get_drvdata(dev);
93+
94+
if (!hba)
95+
return 0;
96+
97+
return ufshcd_runtime_resume(hba);
98+
}
99+
static int ufshcd_pci_runtime_idle(struct device *dev)
100+
{
101+
struct ufs_hba *hba = dev_get_drvdata(dev);
102+
103+
if (!hba)
104+
return 0;
105+
106+
return ufshcd_runtime_idle(hba);
107+
}
108+
#else /* !CONFIG_PM_RUNTIME */
109+
#define ufshcd_pci_runtime_suspend NULL
110+
#define ufshcd_pci_runtime_resume NULL
111+
#define ufshcd_pci_runtime_idle NULL
112+
#endif /* CONFIG_PM_RUNTIME */
113+
76114
/**
77115
* ufshcd_pci_shutdown - main function to put the controller in reset state
78116
* @pdev: pointer to PCI device handle
@@ -91,6 +129,9 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
91129
{
92130
struct ufs_hba *hba = pci_get_drvdata(pdev);
93131

132+
pm_runtime_forbid(&pdev->dev);
133+
pm_runtime_get_noresume(&pdev->dev);
134+
94135
disable_irq(pdev->irq);
95136
ufshcd_remove(hba);
96137
pci_release_regions(pdev);
@@ -168,6 +209,8 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
168209
}
169210

170211
pci_set_drvdata(pdev, hba);
212+
pm_runtime_put_noidle(&pdev->dev);
213+
pm_runtime_allow(&pdev->dev);
171214

172215
return 0;
173216

@@ -182,6 +225,14 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
182225
return err;
183226
}
184227

228+
static const struct dev_pm_ops ufshcd_pci_pm_ops = {
229+
.suspend = ufshcd_pci_suspend,
230+
.resume = ufshcd_pci_resume,
231+
.runtime_suspend = ufshcd_pci_runtime_suspend,
232+
.runtime_resume = ufshcd_pci_runtime_resume,
233+
.runtime_idle = ufshcd_pci_runtime_idle,
234+
};
235+
185236
static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
186237
{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
187238
{ } /* terminate list */
@@ -195,10 +246,9 @@ static struct pci_driver ufshcd_pci_driver = {
195246
.probe = ufshcd_pci_probe,
196247
.remove = ufshcd_pci_remove,
197248
.shutdown = ufshcd_pci_shutdown,
198-
#ifdef CONFIG_PM
199-
.suspend = ufshcd_pci_suspend,
200-
.resume = ufshcd_pci_resume,
201-
#endif
249+
.driver = {
250+
.pm = &ufshcd_pci_pm_ops
251+
},
202252
};
203253

204254
module_pci_driver(ufshcd_pci_driver);

drivers/scsi/ufs/ufshcd-pltfrm.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
*/
3535

3636
#include <linux/platform_device.h>
37+
#include <linux/pm_runtime.h>
3738

3839
#include "ufshcd.h"
3940

@@ -87,6 +88,40 @@ static int ufshcd_pltfrm_resume(struct device *dev)
8788
#define ufshcd_pltfrm_resume NULL
8889
#endif
8990

91+
#ifdef CONFIG_PM_RUNTIME
92+
static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
93+
{
94+
struct ufs_hba *hba = dev_get_drvdata(dev);
95+
96+
if (!hba)
97+
return 0;
98+
99+
return ufshcd_runtime_suspend(hba);
100+
}
101+
static int ufshcd_pltfrm_runtime_resume(struct device *dev)
102+
{
103+
struct ufs_hba *hba = dev_get_drvdata(dev);
104+
105+
if (!hba)
106+
return 0;
107+
108+
return ufshcd_runtime_resume(hba);
109+
}
110+
static int ufshcd_pltfrm_runtime_idle(struct device *dev)
111+
{
112+
struct ufs_hba *hba = dev_get_drvdata(dev);
113+
114+
if (!hba)
115+
return 0;
116+
117+
return ufshcd_runtime_idle(hba);
118+
}
119+
#else /* !CONFIG_PM_RUNTIME */
120+
#define ufshcd_pltfrm_runtime_suspend NULL
121+
#define ufshcd_pltfrm_runtime_resume NULL
122+
#define ufshcd_pltfrm_runtime_idle NULL
123+
#endif /* CONFIG_PM_RUNTIME */
124+
90125
/**
91126
* ufshcd_pltfrm_probe - probe routine of the driver
92127
* @pdev: pointer to Platform device handle
@@ -122,14 +157,22 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
122157
goto out;
123158
}
124159

160+
pm_runtime_set_active(&pdev->dev);
161+
pm_runtime_enable(&pdev->dev);
162+
125163
err = ufshcd_init(dev, &hba, mmio_base, irq);
126164
if (err) {
127165
dev_err(dev, "Intialization failed\n");
128-
goto out;
166+
goto out_disable_rpm;
129167
}
130168

131169
platform_set_drvdata(pdev, hba);
132170

171+
return 0;
172+
173+
out_disable_rpm:
174+
pm_runtime_disable(&pdev->dev);
175+
pm_runtime_set_suspended(&pdev->dev);
133176
out:
134177
return err;
135178
}
@@ -144,6 +187,8 @@ static int ufshcd_pltfrm_remove(struct platform_device *pdev)
144187
{
145188
struct ufs_hba *hba = platform_get_drvdata(pdev);
146189

190+
pm_runtime_get_sync(&(pdev)->dev);
191+
147192
disable_irq(hba->irq);
148193
ufshcd_remove(hba);
149194
return 0;
@@ -157,6 +202,9 @@ static const struct of_device_id ufs_of_match[] = {
157202
static const struct dev_pm_ops ufshcd_dev_pm_ops = {
158203
.suspend = ufshcd_pltfrm_suspend,
159204
.resume = ufshcd_pltfrm_resume,
205+
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
206+
.runtime_resume = ufshcd_pltfrm_runtime_resume,
207+
.runtime_idle = ufshcd_pltfrm_runtime_idle,
160208
};
161209

162210
static struct platform_driver ufshcd_pltfrm_driver = {

drivers/scsi/ufs/ufshcd.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,6 +2169,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
21692169
u32 status = 0;
21702170
hba = container_of(work, struct ufs_hba, eeh_work);
21712171

2172+
pm_runtime_get_sync(hba->dev);
21722173
err = ufshcd_get_ee_status(hba, &status);
21732174
if (err) {
21742175
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -2184,6 +2185,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
21842185
__func__, err);
21852186
}
21862187
out:
2188+
pm_runtime_put_sync(hba->dev);
21872189
return;
21882190
}
21892191

@@ -2196,9 +2198,11 @@ static void ufshcd_fatal_err_handler(struct work_struct *work)
21962198
struct ufs_hba *hba;
21972199
hba = container_of(work, struct ufs_hba, feh_workq);
21982200

2201+
pm_runtime_get_sync(hba->dev);
21992202
/* check if reset is already in progress */
22002203
if (hba->ufshcd_state != UFSHCD_STATE_RESET)
22012204
ufshcd_do_reset(hba);
2205+
pm_runtime_put_sync(hba->dev);
22022206
}
22032207

22042208
/**
@@ -2500,6 +2504,7 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
25002504

25012505
ufshcd_force_reset_auto_bkops(hba);
25022506
scsi_scan_host(hba->host);
2507+
pm_runtime_put_sync(hba->dev);
25032508
out:
25042509
return;
25052510
}
@@ -2721,6 +2726,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
27212726

27222727
*hba_handle = hba;
27232728

2729+
/* Hold auto suspend until async scan completes */
2730+
pm_runtime_get_sync(dev);
2731+
27242732
async_schedule(ufshcd_async_scan, hba);
27252733

27262734
return 0;

0 commit comments

Comments
 (0)