Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 356949
b: refs/heads/master
c: 2133420
h: refs/heads/master
i:
  356947: 13d94ec
v: v3
  • Loading branch information
Aaron Lu authored and Jeff Garzik committed Jan 21, 2013
1 parent 9e85b2a commit 7b81676
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3dc67440d99b2c718ef5f1eb1424a9066ffa3fb9
refs/heads/master: 213342053db58eabdaddff9c036c2b81ca63c443
35 changes: 25 additions & 10 deletions trunk/drivers/ata/libata-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,22 @@ void ata_acpi_on_resume(struct ata_port *ap)
}
}

static int ata_acpi_choose_suspend_state(struct ata_device *dev)
{
int d_max_in = ACPI_STATE_D3_COLD;

/*
* For ATAPI, runtime D3 cold is only allowed
* for ZPODD in zero power ready state
*/
if (dev->class == ATA_DEV_ATAPI &&
!(zpodd_dev_enabled(dev) && zpodd_zpready(dev)))
d_max_in = ACPI_STATE_D3_HOT;

return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev,
NULL, d_max_in);
}

/**
* ata_acpi_set_state - set the port power state
* @ap: target ATA port
Expand All @@ -861,17 +877,16 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
continue;

if (state.event != PM_EVENT_ON) {
acpi_state = acpi_pm_device_sleep_state(
&dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3);
if (acpi_state > 0)
acpi_bus_set_power(handle, acpi_state);
/* TBD: need to check if it's runtime pm request */
acpi_pm_device_run_wake(
&dev->sdev->sdev_gendev, true);
acpi_state = ata_acpi_choose_suspend_state(dev);
if (acpi_state == ACPI_STATE_D0)
continue;
if (zpodd_dev_enabled(dev) &&
acpi_state == ACPI_STATE_D3_COLD)
zpodd_enable_run_wake(dev);
acpi_bus_set_power(handle, acpi_state);
} else {
/* Ditto */
acpi_pm_device_run_wake(
&dev->sdev->sdev_gendev, false);
if (zpodd_dev_enabled(dev))
zpodd_disable_run_wake(dev);
acpi_bus_set_power(handle, ACPI_STATE_D0);
}
}
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -3857,6 +3857,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = atapi_eh_clear_ua(dev);
if (rc)
goto rest_fail;
if (zpodd_dev_enabled(dev))
zpodd_post_poweron(dev);
}
}

Expand Down
83 changes: 83 additions & 0 deletions trunk/drivers/ata/libata-zpodd.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,26 @@ struct zpodd {
bool zp_ready; /* ZP ready state */
unsigned long last_ready; /* last ZP ready timestamp */
bool zp_sampled; /* ZP ready state sampled */
bool powered_off; /* ODD is powered off
* during suspend */
};

static int eject_tray(struct ata_device *dev)
{
struct ata_taskfile tf = {};
const char cdb[] = { GPCMD_START_STOP_UNIT,
0, 0, 0,
0x02, /* LoEj */
0, 0, 0, 0, 0, 0, 0,
};

tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET;
tf.protocol = ATAPI_PROT_NODATA;

return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
}

/* Per the spec, only slot type and drawer type ODD can be supported */
static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
{
Expand Down Expand Up @@ -149,6 +167,71 @@ void zpodd_on_suspend(struct ata_device *dev)
zpodd->zp_ready = true;
}

bool zpodd_zpready(struct ata_device *dev)
{
struct zpodd *zpodd = dev->zpodd;
return zpodd->zp_ready;
}

/*
* Enable runtime wake capability through ACPI and set the powered_off flag,
* this flag will be used during resume to decide what operations are needed
* to take.
*/
void zpodd_enable_run_wake(struct ata_device *dev)
{
struct zpodd *zpodd = dev->zpodd;

zpodd->powered_off = true;
device_set_run_wake(&dev->sdev->sdev_gendev, true);
acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true);
}

/* Disable runtime wake capability if it is enabled */
void zpodd_disable_run_wake(struct ata_device *dev)
{
struct zpodd *zpodd = dev->zpodd;

if (zpodd->powered_off) {
acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false);
device_set_run_wake(&dev->sdev->sdev_gendev, false);
}
}

/*
* Post power on processing after the ODD has been recovered. If the
* ODD wasn't powered off during suspend, it doesn't do anything.
*
* For drawer type ODD, if it is powered on due to user pressed the
* eject button, the tray needs to be ejected. This can only be done
* after the ODD has been recovered, i.e. link is initialized and
* device is able to process NON_DATA PIO command, as eject needs to
* send command for the ODD to process.
*
* The from_notify flag set in wake notification handler function
* zpodd_wake_dev represents if power on is due to user's action.
*
* For both types of ODD, several fields need to be reset.
*/
void zpodd_post_poweron(struct ata_device *dev)
{
struct zpodd *zpodd = dev->zpodd;

if (!zpodd->powered_off)
return;

zpodd->powered_off = false;

if (zpodd->from_notify) {
zpodd->from_notify = false;
if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER)
eject_tray(dev);
}

zpodd->zp_sampled = false;
zpodd->zp_ready = false;
}

static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
{
struct ata_device *ata_dev = context;
Expand Down
8 changes: 8 additions & 0 deletions trunk/drivers/ata/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,19 @@ static inline bool zpodd_dev_enabled(struct ata_device *dev)
return dev->zpodd != NULL;
}
void zpodd_on_suspend(struct ata_device *dev);
bool zpodd_zpready(struct ata_device *dev);
void zpodd_enable_run_wake(struct ata_device *dev);
void zpodd_disable_run_wake(struct ata_device *dev);
void zpodd_post_poweron(struct ata_device *dev);
#else /* CONFIG_SATA_ZPODD */
static inline void zpodd_init(struct ata_device *dev) {}
static inline void zpodd_exit(struct ata_device *dev) {}
static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; }
static inline void zpodd_on_suspend(struct ata_device *dev) {}
static inline bool zpodd_zpready(struct ata_device *dev) { return false; }
static inline void zpodd_enable_run_wake(struct ata_device *dev) {}
static inline void zpodd_disable_run_wake(struct ata_device *dev) {}
static inline void zpodd_post_poweron(struct ata_device *dev) {}
#endif /* CONFIG_SATA_ZPODD */

#endif /* __LIBATA_H__ */

0 comments on commit 7b81676

Please sign in to comment.