lkml.org 
[lkml]   [2011]   [Nov]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 5/6] ata: add ata port system PM callbacks
    Date
    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>
    ---
    drivers/ata/libata-core.c | 144 ++++++++++++++++++++-------------------
    drivers/ata/libata-transport.c | 1 +
    drivers/ata/libata.h | 1 +
    3 files changed, 76 insertions(+), 70 deletions(-)

    diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
    index c04ad68..04c208e 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)
    }

    #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;
    -
    - for (i = 0; i < host->n_ports; i++) {
    - struct ata_port *ap = host->ports[i];
    - struct ata_link *link;
    + int 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);
    - }
    + /* 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);
    + /* request PM ops to EH */
    + spin_lock_irqsave(ap->lock, flags);

    - ap->pm_mesg = mesg;
    - if (wait) {
    - rc = 0;
    - ap->pm_result = &rc;
    - }
    + 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;
    - }
    + 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);
    + ata_port_schedule_eh(ap);

    - spin_unlock_irqrestore(ap->lock, flags);
    + 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;
    - }
    + /* wait and check result */
    + if (wait) {
    + ata_port_wait_eh(ap);
    + WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
    }

    - return 0;
    + 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
    diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
    index ce9dc62..3ceb3d9 100644
    --- a/drivers/ata/libata-transport.c
    +++ b/drivers/ata/libata-transport.c
    @@ -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;
    diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
    index 773de97..814486d 100644
    --- a/drivers/ata/libata.h
    +++ b/drivers/ata/libata.h
    @@ -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);
    --
    1.7.2.5


    \
     
     \ /
      Last update: 2011-11-28 02:19    [W:0.036 / U:0.260 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site