mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-13 22:14:20 +08:00
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
|
#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,
|
unsigned int action, unsigned int ehi_flags,
|
||||||
int wait)
|
int wait)
|
||||||
{
|
{
|
||||||
|
struct ata_link *link;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i, rc;
|
int rc;
|
||||||
|
|
||||||
for (i = 0; i < host->n_ports; i++) {
|
/* Previous resume operation might still be in
|
||||||
struct ata_port *ap = host->ports[i];
|
* progress. Wait for PM_PENDING to clear.
|
||||||
struct ata_link *link;
|
*/
|
||||||
|
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
|
||||||
/* Previous resume operation might still be in
|
ata_port_wait_eh(ap);
|
||||||
* progress. Wait for PM_PENDING to clear.
|
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
* ata_host_suspend - suspend host
|
||||||
* @host: host to suspend
|
* @host: host to suspend
|
||||||
* @mesg: PM message
|
* @mesg: PM message
|
||||||
*
|
*
|
||||||
* Suspend @host. Actual operation is performed by EH. This
|
* Suspend @host. Actual operation is performed by port suspend.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
|
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
|
||||||
{
|
{
|
||||||
unsigned int ehi_flags = ATA_EHI_QUIET;
|
host->dev->power.power_state = mesg;
|
||||||
int rc;
|
return 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_host_resume - resume host
|
* ata_host_resume - resume host
|
||||||
* @host: host to resume
|
* @host: host to resume
|
||||||
*
|
*
|
||||||
* Resume @host. Actual operation is performed by EH. This
|
* Resume @host. Actual operation is performed by port resume.
|
||||||
* function requests EH to perform PM operations and returns.
|
|
||||||
* Note that all resume operations are performed parallelly.
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* Kernel thread context (may sleep).
|
|
||||||
*/
|
*/
|
||||||
void ata_host_resume(struct ata_host *host)
|
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;
|
host->dev->power.power_state = PMSG_ON;
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
* ata_dev_init - Initialize an ata_device structure
|
||||||
* @dev: Device structure to initialize
|
* @dev: Device structure to initialize
|
||||||
|
@ -279,6 +279,7 @@ int ata_tport_add(struct device *parent,
|
|||||||
struct device *dev = &ap->tdev;
|
struct device *dev = &ap->tdev;
|
||||||
|
|
||||||
device_initialize(dev);
|
device_initialize(dev);
|
||||||
|
dev->type = &ata_port_type;
|
||||||
|
|
||||||
dev->parent = get_device(parent);
|
dev->parent = get_device(parent);
|
||||||
dev->release = ata_tport_release;
|
dev->release = ata_tport_release;
|
||||||
|
@ -58,6 +58,7 @@ extern int atapi_passthru16;
|
|||||||
extern int libata_fua;
|
extern int libata_fua;
|
||||||
extern int libata_noacpi;
|
extern int libata_noacpi;
|
||||||
extern int libata_allow_tpm;
|
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 struct ata_link *ata_dev_phys_link(struct ata_device *dev);
|
||||||
extern void ata_force_cbl(struct ata_port *ap);
|
extern void ata_force_cbl(struct ata_port *ap);
|
||||||
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
||||||
|
Loading…
Reference in New Issue
Block a user