[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAF1ivSbhL0-46rnKjHdTBOrJG+9n_cKYF4=fL+HR8YFtmDVZOg@mail.gmail.com>
Date: Wed, 7 Dec 2011 16:38:38 +0800
From: Lin Ming <ming.m.lin@...el.com>
To: Jeff Garzik <jgarzik@...ox.com>,
James Bottomley <JBottomley@...allels.com>,
Alan Stern <stern@...land.harvard.edu>,
Tejun Heo <tj@...nel.org>
Cc: linux-kernel@...r.kernel.org, linux-ide@...r.kernel.org,
linux-scsi@...r.kernel.org, linux-pm@...r.kernel.org,
"Rafael J. Wysocki" <rjw@...k.pl>,
Huang Ying <ying.huang@...el.com>,
Zhang Rui <rui.zhang@...el.com>
Subject: Re: [PATCH v5 5/6] ata: add ata port system PM callbacks
On Mon, Dec 5, 2011 at 9:20 AM, Lin Ming <ming.m.lin@...el.com> wrote:
> 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.
Hi Tejun & Alan,
How about this patch?
Lin Ming
>
> Signed-off-by: Lin Ming <ming.m.lin@...el.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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists