aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2011-12-04 20:20:27 -0500
committerJeff Garzik <jgarzik@redhat.com>2012-01-08 19:14:58 -0500
commit5ef41082912bdfcb33fa53b8dba2ad17dea2ef90 (patch)
treeb63aff744994b75af6c3e5e5e70e01312027992e /drivers/ata
parent54f57588463db1105f4a93b2902a6f95cb8f796a (diff)
ata: add ata port system PM callbacks
Change ata_host_request_pm to ata_port_request_pm which performs port suspend/resume. Add ata port type driver which implements port PM callbacks. Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-core.c144
-rw-r--r--drivers/ata/libata-transport.c1
-rw-r--r--drivers/ata/libata.h1
3 files changed, 76 insertions, 70 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c04ad68cb602..04c208e3cec6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5234,112 +5234,116 @@ bool ata_link_offline(struct ata_link *link)
5234} 5234}
5235 5235
5236#ifdef CONFIG_PM 5236#ifdef CONFIG_PM
5237static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, 5237static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
5238 unsigned int action, unsigned int ehi_flags, 5238 unsigned int action, unsigned int ehi_flags,
5239 int wait) 5239 int wait)
5240{ 5240{
5241 struct ata_link *link;
5241 unsigned long flags; 5242 unsigned long flags;
5242 int i, rc; 5243 int rc;
5243
5244 for (i = 0; i < host->n_ports; i++) {
5245 struct ata_port *ap = host->ports[i];
5246 struct ata_link *link;
5247 5244
5248 /* Previous resume operation might still be in 5245 /* Previous resume operation might still be in
5249 * progress. Wait for PM_PENDING to clear. 5246 * progress. Wait for PM_PENDING to clear.
5250 */ 5247 */
5251 if (ap->pflags & ATA_PFLAG_PM_PENDING) { 5248 if (ap->pflags & ATA_PFLAG_PM_PENDING) {
5252 ata_port_wait_eh(ap); 5249 ata_port_wait_eh(ap);
5253 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); 5250 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
5254 } 5251 }
5255 5252
5256 /* request PM ops to EH */ 5253 /* request PM ops to EH */
5257 spin_lock_irqsave(ap->lock, flags); 5254 spin_lock_irqsave(ap->lock, flags);
5258 5255
5259 ap->pm_mesg = mesg; 5256 ap->pm_mesg = mesg;
5260 if (wait) { 5257 if (wait) {
5261 rc = 0; 5258 rc = 0;
5262 ap->pm_result = &rc; 5259 ap->pm_result = &rc;
5263 } 5260 }
5264 5261
5265 ap->pflags |= ATA_PFLAG_PM_PENDING; 5262 ap->pflags |= ATA_PFLAG_PM_PENDING;
5266 ata_for_each_link(link, ap, HOST_FIRST) { 5263 ata_for_each_link(link, ap, HOST_FIRST) {
5267 link->eh_info.action |= action; 5264 link->eh_info.action |= action;
5268 link->eh_info.flags |= ehi_flags; 5265 link->eh_info.flags |= ehi_flags;
5269 } 5266 }
5270 5267
5271 ata_port_schedule_eh(ap); 5268 ata_port_schedule_eh(ap);
5272 5269
5273 spin_unlock_irqrestore(ap->lock, flags); 5270 spin_unlock_irqrestore(ap->lock, flags);
5274 5271
5275 /* wait and check result */ 5272 /* wait and check result */
5276 if (wait) { 5273 if (wait) {
5277 ata_port_wait_eh(ap); 5274 ata_port_wait_eh(ap);
5278 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); 5275 WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
5279 if (rc)
5280 return rc;
5281 }
5282 } 5276 }
5283 5277
5284 return 0; 5278 return rc;
5285} 5279}
5286 5280
5281#define to_ata_port(d) container_of(d, struct ata_port, tdev)
5282
5283static int ata_port_suspend_common(struct device *dev)
5284{
5285 struct ata_port *ap = to_ata_port(dev);
5286 int rc;
5287
5288 rc = ata_port_request_pm(ap, PMSG_SUSPEND, 0, ATA_EHI_QUIET, 1);
5289 return rc;
5290}
5291
5292static int ata_port_suspend(struct device *dev)
5293{
5294 if (pm_runtime_suspended(dev))
5295 return 0;
5296
5297 return ata_port_suspend_common(dev);
5298}
5299
5300static int ata_port_resume(struct device *dev)
5301{
5302 struct ata_port *ap = to_ata_port(dev);
5303 int rc;
5304
5305 rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
5306 ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
5307 return rc;
5308}
5309
5310static const struct dev_pm_ops ata_port_pm_ops = {
5311 .suspend = ata_port_suspend,
5312 .resume = ata_port_resume,
5313};
5314
5287/** 5315/**
5288 * ata_host_suspend - suspend host 5316 * ata_host_suspend - suspend host
5289 * @host: host to suspend 5317 * @host: host to suspend
5290 * @mesg: PM message 5318 * @mesg: PM message
5291 * 5319 *
5292 * Suspend @host. Actual operation is performed by EH. This 5320 * Suspend @host. Actual operation is performed by port suspend.
5293 * function requests EH to perform PM operations and waits for EH
5294 * to finish.
5295 *
5296 * LOCKING:
5297 * Kernel thread context (may sleep).
5298 *
5299 * RETURNS:
5300 * 0 on success, -errno on failure.
5301 */ 5321 */
5302int ata_host_suspend(struct ata_host *host, pm_message_t mesg) 5322int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
5303{ 5323{
5304 unsigned int ehi_flags = ATA_EHI_QUIET; 5324 host->dev->power.power_state = mesg;
5305 int rc; 5325 return 0;
5306
5307 /*
5308 * On some hardware, device fails to respond after spun down
5309 * for suspend. As the device won't be used before being
5310 * resumed, we don't need to touch the device. Ask EH to skip
5311 * the usual stuff and proceed directly to suspend.
5312 *
5313 * http://thread.gmane.org/gmane.linux.ide/46764
5314 */
5315 if (mesg.event == PM_EVENT_SUSPEND)
5316 ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
5317
5318 rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1);
5319 if (rc == 0)
5320 host->dev->power.power_state = mesg;
5321 return rc;
5322} 5326}
5323 5327
5324/** 5328/**
5325 * ata_host_resume - resume host 5329 * ata_host_resume - resume host
5326 * @host: host to resume 5330 * @host: host to resume
5327 * 5331 *
5328 * Resume @host. Actual operation is performed by EH. This 5332 * Resume @host. Actual operation is performed by port resume.
5329 * function requests EH to perform PM operations and returns.
5330 * Note that all resume operations are performed parallelly.
5331 *
5332 * LOCKING:
5333 * Kernel thread context (may sleep).
5334 */ 5333 */
5335void ata_host_resume(struct ata_host *host) 5334void ata_host_resume(struct ata_host *host)
5336{ 5335{
5337 ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
5338 ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
5339 host->dev->power.power_state = PMSG_ON; 5336 host->dev->power.power_state = PMSG_ON;
5340} 5337}
5341#endif 5338#endif
5342 5339
5340struct device_type ata_port_type = {
5341 .name = "ata_port",
5342#ifdef CONFIG_PM
5343 .pm = &ata_port_pm_ops,
5344#endif
5345};
5346
5343/** 5347/**
5344 * ata_dev_init - Initialize an ata_device structure 5348 * ata_dev_init - Initialize an ata_device structure
5345 * @dev: Device structure to initialize 5349 * @dev: Device structure to initialize
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index ce9dc6207f37..3ceb3d94be26 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -279,6 +279,7 @@ int ata_tport_add(struct device *parent,
279 struct device *dev = &ap->tdev; 279 struct device *dev = &ap->tdev;
280 280
281 device_initialize(dev); 281 device_initialize(dev);
282 dev->type = &ata_port_type;
282 283
283 dev->parent = get_device(parent); 284 dev->parent = get_device(parent);
284 dev->release = ata_tport_release; 285 dev->release = ata_tport_release;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 773de97988a2..814486d35c44 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -58,6 +58,7 @@ extern int atapi_passthru16;
58extern int libata_fua; 58extern int libata_fua;
59extern int libata_noacpi; 59extern int libata_noacpi;
60extern int libata_allow_tpm; 60extern int libata_allow_tpm;
61extern struct device_type ata_port_type;
61extern struct ata_link *ata_dev_phys_link(struct ata_device *dev); 62extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
62extern void ata_force_cbl(struct ata_port *ap); 63extern void ata_force_cbl(struct ata_port *ap);
63extern u64 ata_tf_to_lba(const struct ata_taskfile *tf); 64extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);