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>
This commit is contained in:
parent
54f5758846
commit
5ef4108291
@ -5234,112 +5234,116 @@ bool ata_link_offline(struct ata_link *link)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
|
||||
static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
|
||||
unsigned int action, unsigned int ehi_flags,
|
||||
int wait)
|
||||
{
|
||||
struct ata_link *link;
|
||||
unsigned long flags;
|
||||
int i, rc;
|
||||
int rc;
|
||||
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
struct ata_port *ap = host->ports[i];
|
||||
struct ata_link *link;
|
||||
|
||||
/* Previous resume operation might still be in
|
||||
* progress. Wait for PM_PENDING to clear.
|
||||
*/
|
||||
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
|
||||
ata_port_wait_eh(ap);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||
}
|
||||
|
||||
/* request PM ops to EH */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ap->pm_mesg = mesg;
|
||||
if (wait) {
|
||||
rc = 0;
|
||||
ap->pm_result = &rc;
|
||||
}
|
||||
|
||||
ap->pflags |= ATA_PFLAG_PM_PENDING;
|
||||
ata_for_each_link(link, ap, HOST_FIRST) {
|
||||
link->eh_info.action |= action;
|
||||
link->eh_info.flags |= ehi_flags;
|
||||
}
|
||||
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* wait and check result */
|
||||
if (wait) {
|
||||
ata_port_wait_eh(ap);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
/* Previous resume operation might still be in
|
||||
* progress. Wait for PM_PENDING to clear.
|
||||
*/
|
||||
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
|
||||
ata_port_wait_eh(ap);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* request PM ops to EH */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ap->pm_mesg = mesg;
|
||||
if (wait) {
|
||||
rc = 0;
|
||||
ap->pm_result = &rc;
|
||||
}
|
||||
|
||||
ap->pflags |= ATA_PFLAG_PM_PENDING;
|
||||
ata_for_each_link(link, ap, HOST_FIRST) {
|
||||
link->eh_info.action |= action;
|
||||
link->eh_info.flags |= ehi_flags;
|
||||
}
|
||||
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* wait and check result */
|
||||
if (wait) {
|
||||
ata_port_wait_eh(ap);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
|
||||
|
||||
static int ata_port_suspend_common(struct device *dev)
|
||||
{
|
||||
struct ata_port *ap = to_ata_port(dev);
|
||||
int rc;
|
||||
|
||||
rc = ata_port_request_pm(ap, PMSG_SUSPEND, 0, ATA_EHI_QUIET, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ata_port_suspend(struct device *dev)
|
||||
{
|
||||
if (pm_runtime_suspended(dev))
|
||||
return 0;
|
||||
|
||||
return ata_port_suspend_common(dev);
|
||||
}
|
||||
|
||||
static int ata_port_resume(struct device *dev)
|
||||
{
|
||||
struct ata_port *ap = to_ata_port(dev);
|
||||
int rc;
|
||||
|
||||
rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
|
||||
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ata_port_pm_ops = {
|
||||
.suspend = ata_port_suspend,
|
||||
.resume = ata_port_resume,
|
||||
};
|
||||
|
||||
/**
|
||||
* ata_host_suspend - suspend host
|
||||
* @host: host to suspend
|
||||
* @mesg: PM message
|
||||
*
|
||||
* Suspend @host. Actual operation is performed by EH. This
|
||||
* function requests EH to perform PM operations and waits for EH
|
||||
* to finish.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -errno on failure.
|
||||
* Suspend @host. Actual operation is performed by port suspend.
|
||||
*/
|
||||
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
|
||||
{
|
||||
unsigned int ehi_flags = ATA_EHI_QUIET;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* On some hardware, device fails to respond after spun down
|
||||
* for suspend. As the device won't be used before being
|
||||
* resumed, we don't need to touch the device. Ask EH to skip
|
||||
* the usual stuff and proceed directly to suspend.
|
||||
*
|
||||
* http://thread.gmane.org/gmane.linux.ide/46764
|
||||
*/
|
||||
if (mesg.event == PM_EVENT_SUSPEND)
|
||||
ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
|
||||
|
||||
rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1);
|
||||
if (rc == 0)
|
||||
host->dev->power.power_state = mesg;
|
||||
return rc;
|
||||
host->dev->power.power_state = mesg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_host_resume - resume host
|
||||
* @host: host to resume
|
||||
*
|
||||
* Resume @host. Actual operation is performed by EH. This
|
||||
* function requests EH to perform PM operations and returns.
|
||||
* Note that all resume operations are performed parallelly.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
* Resume @host. Actual operation is performed by port resume.
|
||||
*/
|
||||
void ata_host_resume(struct ata_host *host)
|
||||
{
|
||||
ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
|
||||
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
|
||||
host->dev->power.power_state = PMSG_ON;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct device_type ata_port_type = {
|
||||
.name = "ata_port",
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &ata_port_pm_ops,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* ata_dev_init - Initialize an ata_device structure
|
||||
* @dev: Device structure to initialize
|
||||
|
@ -279,6 +279,7 @@ int ata_tport_add(struct device *parent,
|
||||
struct device *dev = &ap->tdev;
|
||||
|
||||
device_initialize(dev);
|
||||
dev->type = &ata_port_type;
|
||||
|
||||
dev->parent = get_device(parent);
|
||||
dev->release = ata_tport_release;
|
||||
|
@ -58,6 +58,7 @@ extern int atapi_passthru16;
|
||||
extern int libata_fua;
|
||||
extern int libata_noacpi;
|
||||
extern int libata_allow_tpm;
|
||||
extern struct device_type ata_port_type;
|
||||
extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
|
||||
extern void ata_force_cbl(struct ata_port *ap);
|
||||
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
||||
|
Loading…
Reference in New Issue
Block a user