diff options
Diffstat (limited to 'drivers/scsi/scsi_pm.c')
| -rw-r--r-- | drivers/scsi/scsi_pm.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index cd83758ce0a2..d70e91ae60af 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c | |||
| @@ -59,6 +59,12 @@ static int scsi_bus_resume_common(struct device *dev) | |||
| 59 | 59 | ||
| 60 | if (scsi_is_sdev_device(dev)) | 60 | if (scsi_is_sdev_device(dev)) |
| 61 | err = scsi_dev_type_resume(dev); | 61 | err = scsi_dev_type_resume(dev); |
| 62 | |||
| 63 | if (err == 0) { | ||
| 64 | pm_runtime_disable(dev); | ||
| 65 | pm_runtime_set_active(dev); | ||
| 66 | pm_runtime_enable(dev); | ||
| 67 | } | ||
| 62 | return err; | 68 | return err; |
| 63 | } | 69 | } |
| 64 | 70 | ||
| @@ -86,6 +92,107 @@ static int scsi_bus_poweroff(struct device *dev) | |||
| 86 | 92 | ||
| 87 | #endif /* CONFIG_PM_SLEEP */ | 93 | #endif /* CONFIG_PM_SLEEP */ |
| 88 | 94 | ||
| 95 | #ifdef CONFIG_PM_RUNTIME | ||
| 96 | |||
| 97 | static int scsi_runtime_suspend(struct device *dev) | ||
| 98 | { | ||
| 99 | int err = 0; | ||
| 100 | |||
| 101 | dev_dbg(dev, "scsi_runtime_suspend\n"); | ||
| 102 | if (scsi_is_sdev_device(dev)) { | ||
| 103 | err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND); | ||
| 104 | if (err == -EAGAIN) | ||
| 105 | pm_schedule_suspend(dev, jiffies_to_msecs( | ||
| 106 | round_jiffies_up_relative(HZ/10))); | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Insert hooks here for targets, hosts, and transport classes */ | ||
| 110 | |||
| 111 | return err; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int scsi_runtime_resume(struct device *dev) | ||
| 115 | { | ||
| 116 | int err = 0; | ||
| 117 | |||
| 118 | dev_dbg(dev, "scsi_runtime_resume\n"); | ||
| 119 | if (scsi_is_sdev_device(dev)) | ||
| 120 | err = scsi_dev_type_resume(dev); | ||
| 121 | |||
| 122 | /* Insert hooks here for targets, hosts, and transport classes */ | ||
| 123 | |||
| 124 | return err; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int scsi_runtime_idle(struct device *dev) | ||
| 128 | { | ||
| 129 | int err; | ||
| 130 | |||
| 131 | dev_dbg(dev, "scsi_runtime_idle\n"); | ||
| 132 | |||
| 133 | /* Insert hooks here for targets, hosts, and transport classes */ | ||
| 134 | |||
| 135 | if (scsi_is_sdev_device(dev)) | ||
| 136 | err = pm_schedule_suspend(dev, 100); | ||
| 137 | else | ||
| 138 | err = pm_runtime_suspend(dev); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | int scsi_autopm_get_device(struct scsi_device *sdev) | ||
| 143 | { | ||
| 144 | int err; | ||
| 145 | |||
| 146 | err = pm_runtime_get_sync(&sdev->sdev_gendev); | ||
| 147 | if (err < 0) | ||
| 148 | pm_runtime_put_sync(&sdev->sdev_gendev); | ||
| 149 | else if (err > 0) | ||
| 150 | err = 0; | ||
| 151 | return err; | ||
| 152 | } | ||
| 153 | EXPORT_SYMBOL_GPL(scsi_autopm_get_device); | ||
| 154 | |||
| 155 | void scsi_autopm_put_device(struct scsi_device *sdev) | ||
| 156 | { | ||
| 157 | pm_runtime_put_sync(&sdev->sdev_gendev); | ||
| 158 | } | ||
| 159 | EXPORT_SYMBOL_GPL(scsi_autopm_put_device); | ||
| 160 | |||
| 161 | void scsi_autopm_get_target(struct scsi_target *starget) | ||
| 162 | { | ||
| 163 | pm_runtime_get_sync(&starget->dev); | ||
| 164 | } | ||
| 165 | |||
| 166 | void scsi_autopm_put_target(struct scsi_target *starget) | ||
| 167 | { | ||
| 168 | pm_runtime_put_sync(&starget->dev); | ||
| 169 | } | ||
| 170 | |||
| 171 | int scsi_autopm_get_host(struct Scsi_Host *shost) | ||
| 172 | { | ||
| 173 | int err; | ||
| 174 | |||
| 175 | err = pm_runtime_get_sync(&shost->shost_gendev); | ||
| 176 | if (err < 0) | ||
| 177 | pm_runtime_put_sync(&shost->shost_gendev); | ||
| 178 | else if (err > 0) | ||
| 179 | err = 0; | ||
| 180 | return err; | ||
| 181 | } | ||
| 182 | |||
| 183 | void scsi_autopm_put_host(struct Scsi_Host *shost) | ||
| 184 | { | ||
| 185 | pm_runtime_put_sync(&shost->shost_gendev); | ||
| 186 | } | ||
| 187 | |||
| 188 | #else | ||
| 189 | |||
| 190 | #define scsi_runtime_suspend NULL | ||
| 191 | #define scsi_runtime_resume NULL | ||
| 192 | #define scsi_runtime_idle NULL | ||
| 193 | |||
| 194 | #endif /* CONFIG_PM_RUNTIME */ | ||
| 195 | |||
| 89 | const struct dev_pm_ops scsi_bus_pm_ops = { | 196 | const struct dev_pm_ops scsi_bus_pm_ops = { |
| 90 | .suspend = scsi_bus_suspend, | 197 | .suspend = scsi_bus_suspend, |
| 91 | .resume = scsi_bus_resume_common, | 198 | .resume = scsi_bus_resume_common, |
| @@ -93,4 +200,7 @@ const struct dev_pm_ops scsi_bus_pm_ops = { | |||
| 93 | .thaw = scsi_bus_resume_common, | 200 | .thaw = scsi_bus_resume_common, |
| 94 | .poweroff = scsi_bus_poweroff, | 201 | .poweroff = scsi_bus_poweroff, |
| 95 | .restore = scsi_bus_resume_common, | 202 | .restore = scsi_bus_resume_common, |
| 203 | .runtime_suspend = scsi_runtime_suspend, | ||
| 204 | .runtime_resume = scsi_runtime_resume, | ||
| 205 | .runtime_idle = scsi_runtime_idle, | ||
| 96 | }; | 206 | }; |
