* [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 16:32 ` Jeff Garzik
2006-06-12 15:50 ` [PATCH 03/10] libata: move ata_do_simple_cmd() right below ata_exec_internal() Tejun Heo
` (12 subsequent siblings)
13 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
The controller only needs to be powered down on PMSG_SUSPEND. Skip
powering down for all other messages. This makes disk suspend prep
cycle more efficient and helps controllers which have problems waking
up from D3hot without intervening power removal.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
85016ad86323924d10dc99ac9d7e9e5c0b967b8e
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9a3bd15..51d3b4b 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -5661,7 +5661,10 @@ int ata_pci_device_suspend(struct pci_de
{
pci_save_state(pdev);
pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
+
+ if (state.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
return 0;
}
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 04/10] libata: update ata_do_simple_cmd()
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (2 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 02/10] libata: kill per-device PM Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 09/10] sata_sil24: separate out sil24_init_controller() Tejun Heo
` (9 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
* export ata_do_simple_cmd() in drivers/scsi/libata.h
* add proper leading comment
* fix return value
* don't print error message. it's the caller's responsibility
This will be used by new PM.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 25 ++++++++++++++-----------
drivers/scsi/libata.h | 1 +
2 files changed, 15 insertions(+), 11 deletions(-)
722e4a01585700ae416ae7c7a746fd6835ddae34
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 4fc8759..ba9f346 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1123,14 +1123,22 @@ unsigned ata_exec_internal(struct ata_de
return err_mask;
}
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
+/* ata_do_simple_cmd - execute simple internal command
+ * @dev: Device to which the command is sent
+ * @cmd: Opcode to execute
+ *
+ * Execute a 'simple' command, that only consists of the opcode
+ * 'cmd' itself, without filling any other registers
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
*/
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
{
struct ata_taskfile tf;
- int err;
ata_tf_init(dev, &tf);
@@ -1138,12 +1146,7 @@ static int ata_do_simple_cmd(struct ata_
tf.flags |= ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
- __FUNCTION__, err);
-
- return err;
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
}
/**
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index bdd4888..539b0b5 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -50,6 +50,7 @@ extern void ata_port_flush_task(struct a
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen);
+extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
int post_reset, u16 *id);
extern int ata_dev_configure(struct ata_device *dev, int print_info);
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 03/10] libata: move ata_do_simple_cmd() right below ata_exec_internal()
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
2006-06-12 15:50 ` [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 02/10] libata: kill per-device PM Tejun Heo
` (11 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Move ata_do_simple_cmd() right below ata_exec_internal().
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 46 ++++++++++++++++++++++----------------------
1 files changed, 23 insertions(+), 23 deletions(-)
0b531e7f20027038fe1fb44e301fe0e4e88abbb8
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d9fdbbd..4fc8759 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1123,6 +1123,29 @@ unsigned ata_exec_internal(struct ata_de
return err_mask;
}
+/*
+ * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
+ * without filling any other registers
+ */
+static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+{
+ struct ata_taskfile tf;
+ int err;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = cmd;
+ tf.flags |= ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
+ __FUNCTION__, err);
+
+ return err;
+}
+
/**
* ata_pio_need_iordy - check if iordy needed
* @adev: ATA device
@@ -4924,29 +4947,6 @@ int ata_port_offline(struct ata_port *ap
return 0;
}
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
- */
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
-{
- struct ata_taskfile tf;
- int err;
-
- ata_tf_init(dev, &tf);
-
- tf.command = cmd;
- tf.flags |= ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
- __FUNCTION__, err);
-
- return err;
-}
-
/**
* ata_port_start - Set port up for dma.
* @ap: Port to initialize
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 02/10] libata: kill per-device PM
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
2006-06-12 15:50 ` [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND Tejun Heo
2006-06-12 15:50 ` [PATCH 03/10] libata: move ata_do_simple_cmd() right below ata_exec_internal() Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 04/10] libata: update ata_do_simple_cmd() Tejun Heo
` (10 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
As new PM implementation will expand the existing controller-wide PM
to trigger ATA bus wide PM operations, it collides with per-device PM.
Kill per-device PM in preparation for new PM framework.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/ata_piix.c | 2 -
drivers/scsi/libata-core.c | 83 --------------------------------------------
drivers/scsi/libata-scsi.c | 16 --------
include/linux/libata.h | 4 --
4 files changed, 0 insertions(+), 105 deletions(-)
aa2de6bd3de34adcf6a736a70e88f90aba652c3b
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 521b718..75aa47f 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -220,8 +220,6 @@ static struct scsi_host_template piix_sh
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
- .resume = ata_scsi_device_resume,
- .suspend = ata_scsi_device_suspend,
};
static const struct ata_port_operations piix_pata_ops = {
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 51d3b4b..d9fdbbd 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4947,84 +4947,6 @@ static int ata_do_simple_cmd(struct ata_
return err;
}
-static int ata_flush_cache(struct ata_device *dev)
-{
- u8 cmd;
-
- if (!ata_try_flush_cache(dev))
- return 0;
-
- if (ata_id_has_flush_ext(dev->id))
- cmd = ATA_CMD_FLUSH_EXT;
- else
- cmd = ATA_CMD_FLUSH;
-
- return ata_do_simple_cmd(dev, cmd);
-}
-
-static int ata_standby_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
-}
-
-static int ata_start_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
-}
-
-/**
- * ata_device_resume - wakeup a previously suspended devices
- * @dev: the device to resume
- *
- * Kick the drive back into action, by sending it an idle immediate
- * command and making sure its transfer mode matches between drive
- * and host.
- *
- */
-int ata_device_resume(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
-
- if (ap->flags & ATA_FLAG_SUSPENDED) {
- struct ata_device *failed_dev;
-
- ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
-
- ap->flags &= ~ATA_FLAG_SUSPENDED;
- while (ata_set_mode(ap, &failed_dev))
- ata_dev_disable(failed_dev);
- }
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_start_drive(dev);
-
- return 0;
-}
-
-/**
- * ata_device_suspend - prepare a device for suspend
- * @dev: the device to suspend
- * @state: target power management state
- *
- * Flush the cache on the drive, if appropriate, then issue a
- * standbynow command.
- */
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
-{
- struct ata_port *ap = dev->ap;
-
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(dev);
-
- if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(dev);
- ap->flags |= ATA_FLAG_SUSPENDED;
- return 0;
-}
-
/**
* ata_port_start - Set port up for dma.
* @ap: Port to initialize
@@ -5872,11 +5794,6 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
-EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
-EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
-
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_port_abort);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 45a49be..0c30e6c 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -399,22 +399,6 @@ void ata_dump_status(unsigned id, struct
}
}
-int ata_scsi_device_resume(struct scsi_device *sdev)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- return ata_device_resume(dev);
-}
-
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- return ata_device_suspend(dev, state);
-}
-
/**
* ata_to_sense_error - convert ATA error to SCSI error
* @id: ATA device number
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 369f821..17c8ced 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -657,10 +657,6 @@ extern int sata_scr_write(struct ata_por
extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap);
-extern int ata_scsi_device_resume(struct scsi_device *);
-extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
-extern int ata_device_resume(struct ata_device *);
-extern int ata_device_suspend(struct ata_device *, pm_message_t state);
extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat,
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCHSET] new Power Management for libata
@ 2006-06-12 15:50 Tejun Heo
2006-06-12 15:50 ` [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND Tejun Heo
` (13 more replies)
0 siblings, 14 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide, htejun
Hello, all.
This patchset implements new Power Management for libata. Currently,
only controller-wide suspend and resume are supported. No per-device
power management yet. Both memsleep and disksleep work on supported
controllers.
All PM operations are performed by EH and thus fully synchronized w/
EH. Suspend/resume operations should be safe under all circumstances
as long as libata is concerned. Attaching/detaching/exchanging
devices while sleeping is allowed and handled correctly.
ata_piix, sata_sil and sata_sil24 are updated to use new PM. PM is
tested on the following machines.
* ASUS P5LD2: sky2 disabled as it oopses on PM
O ICH7R in piix mode (advanced/compatible)
O sil3112 PCI card
O sil3114 PCI card
O sil3124 PCI-x card on PCI slot
X sil3132 failed probably due to PCI-e PM problem
* Fujitsu lifebook P7120: enabled ATA_ENABLE_PATA and added entry for
0x266f in ata_piix pci table. Net console makes resume from
memsleep fail.
O ICH6M in piix mode
O sil3112 PCMCIA card
This patchset contains 10 patches.
#01-04 prep for new PM
#05-06 implement new PM
#07-10 update LLDs
This patchset is against
upstream (aeb2ecd6096182cc080d37679080c0f088dcd4a4)
+ [1] kill-ATA_FLAG_SRST patch
+ [2] shift-ATA_FLAG_-bits patch
Jens, Mark, can you guys please test if this patch works on your
notebooks? Note that AHCI isn't updated yet.
Zhao, can you port your AHCI PM stuff over this? This should solve
the problem you talked about in the other mail. Recent changes update
ahci such that it listens to more PHY events for hotplug and that
causes EH to kick in after resuming. The original PM implementation
didn't synchronize w/ EH and thus caused problems.
This patchset is for review only.
Thanks.
--
tejun
[1] http://marc.theaimsgroup.com/?l=linux-ide&m=115012501502940&w=2
[2] http://marc.theaimsgroup.com/?l=linux-ide&m=115012349728574&w=2
^ permalink raw reply [flat|nested] 39+ messages in thread
* [PATCH 07/10] sata_sil: separate out sil_init_controller()
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (6 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 08/10] sata_sil: " Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP Tejun Heo
` (5 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Separate out controller initialization from sil_init_one() into
sil_init_controller(). This will be used by resume.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/sata_sil.c | 86 ++++++++++++++++++++++++++---------------------
1 files changed, 48 insertions(+), 38 deletions(-)
6b3d220117016445f055a0244516cb5de4c8dbe9
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index a7e99a1..4bff260 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -526,6 +526,52 @@ static void sil_dev_config(struct ata_po
}
}
+static void sil_init_controller(struct pci_dev *pdev,
+ int n_ports, unsigned long host_flags,
+ void __iomem *mmio_base)
+{
+ u8 cls;
+ u32 tmp;
+ int i;
+
+ /* Initialize FIFO PCI bus arbitration */
+ cls = sil_get_device_cache_line(pdev);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ for (i = 0; i < n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
+ } else
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "cache line size not set. Driver may not function\n");
+
+ /* Apply R_ERR on DMA activate FIS errata workaround */
+ if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ int cnt;
+
+ for (i = 0, cnt = 0; i < n_ports; i++) {
+ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+ if ((tmp & 0x3) != 0x01)
+ continue;
+ if (!cnt)
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying R_ERR on DMA activate "
+ "FIS errata fix\n");
+ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+ cnt++;
+ }
+ }
+
+ if (n_ports == 4) {
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + sil_port[2].bmdma);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + sil_port[2].bmdma);
+ }
+}
+
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -535,8 +581,6 @@ static int sil_init_one (struct pci_dev
int rc;
unsigned int i;
int pci_dev_busy = 0;
- u32 tmp;
- u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -595,42 +639,8 @@ static int sil_init_one (struct pci_dev
ata_std_ports(&probe_ent->port[i]);
}
- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < probe_ent->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
-
- /* Apply R_ERR on DMA activate FIS errata workaround */
- if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
- int cnt;
-
- for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
- if ((tmp & 0x3) != 0x01)
- continue;
- if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
- cnt++;
- }
- }
-
- if (ent->driver_data == sil_3114) {
- /* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + sil_port[2].bmdma);
- if ((tmp & SIL_INTR_STEERING) == 0)
- writel(tmp | SIL_INTR_STEERING,
- mmio_base + sil_port[2].bmdma);
- }
+ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ mmio_base);
pci_set_master(pdev);
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 10/10] sata_sil24: add suspend/sleep support
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (4 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 09/10] sata_sil24: separate out sil24_init_controller() Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 08/10] sata_sil: " Tejun Heo
` (7 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Add suspend/sleep support.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/sata_sil24.c | 19 +++++++++++++++++++
1 files changed, 19 insertions(+), 0 deletions(-)
79fd0e52c2c53999865a61f160919a0a6308dbc8
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 7726e6e..8c438ba 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/*
* Port registers
@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_p
static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil24_pci_device_resume(struct pci_dev *pdev);
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_drive
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */
+ .suspend = ata_pci_device_suspend,
+ .resume = sil24_pci_device_resume,
};
static struct scsi_host_template sil24_sht = {
@@ -1179,6 +1183,21 @@ static int sil24_init_one(struct pci_dev
return rc;
}
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+ struct sil24_host_priv *hpriv = host_set->private_data;
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+ sil24_init_controller(pdev, host_set->n_ports,
+ host_set->ports[0]->flags,
+ hpriv->host_base, hpriv->port_base);
+
+ return ata_pci_device_resume(pdev);
+}
+
static int __init sil24_init(void)
{
return pci_module_init(&sil24_pci_driver);
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 09/10] sata_sil24: separate out sil24_init_controller()
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (3 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 04/10] libata: update ata_do_simple_cmd() Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 10/10] sata_sil24: add suspend/sleep support Tejun Heo
` (8 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Separate out controller initialization from sil24_init_one() into
sil24_init_controller(). This will be used by resume.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/sata_sil24.c | 107 ++++++++++++++++++++++++++-------------------
1 files changed, 62 insertions(+), 45 deletions(-)
d7124568707660f0a347a158051cf7533478edcf
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index c8b477c..7726e6e 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -988,6 +988,64 @@ static void sil24_host_stop(struct ata_h
kfree(hpriv);
}
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+ unsigned long host_flags,
+ void __iomem *host_base,
+ void __iomem *port_base)
+{
+ u32 tmp;
+ int i;
+
+ /* GPIO off */
+ writel(0, host_base + HOST_FLASH_CMD);
+
+ /* clear global reset & mask interrupts during initialization */
+ writel(0, host_base + HOST_CTRL);
+
+ /* init ports */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+ /* Initial PHY setting */
+ writel(0x20c, port + PORT_PHY_CFG);
+
+ /* Clear port RST */
+ tmp = readl(port + PORT_CTRL_STAT);
+ if (tmp & PORT_CS_PORT_RST) {
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
+ if (tmp & PORT_CS_PORT_RST)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to clear port RST\n");
+ }
+
+ /* Configure IRQ WoC */
+ if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* Zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* Clear port multiplier enable and resume bits */
+ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+ }
+
+ /* Turn on interrupts */
+ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1076,9 +1134,6 @@ static int sil24_init_one(struct pci_dev
}
}
- /* GPIO off */
- writel(0, host_base + HOST_FLASH_CMD);
-
/* Apply workaround for completion IRQ loss on PCI-X errata */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL);
@@ -1090,56 +1145,18 @@ static int sil24_init_one(struct pci_dev
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
- /* clear global reset & mask interrupts during initialization */
- writel(0, host_base + HOST_CTRL);
-
for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
- unsigned long portu = (unsigned long)port;
+ unsigned long portu =
+ (unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
-
- /* Initial PHY setting */
- writel(0x20c, port + PORT_PHY_CFG);
-
- /* Clear port RST */
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_PORT_RST) {
- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_PORT_RST,
- PORT_CS_PORT_RST, 10, 100);
- if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to clear port RST\n");
- }
-
- /* Configure IRQ WoC */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
- /* Turn on interrupts */
- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ host_base, port_base);
pci_set_master(pdev);
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (8 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 16:34 ` Alan Cox
` (4 more replies)
2006-06-12 15:57 ` [PATCHSET] new Power Management for libata Tejun Heo
` (3 subsequent siblings)
13 siblings, 5 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Implement new Power Management framework. All PM operations are
bus-wide and performed by EH. ata_host_set_suspend() and
ata_host_set_resume() are used to request PM suspend and resume on all
ports of a host_set. PCI suspend/resume callbacks calls these two
functions for each host_set the controller implements.
Suspend is performed parallely on all ports of a host_set and resume
is done parallely in background to decrease the time necessary before
responding to user.
New PM is fully synchronized w/ all other EH events and it's safe to
suspend and resume any time. All the usual EH stuff is performed on
resume and removing device or exchanging them while suspended
shouldn't cause any trouble for libata.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 140 ++++++++++++++++++++++++++++++++++++++++--
drivers/scsi/libata-eh.c | 148 +++++++++++++++++++++++++++++++++++++++++++-
include/linux/libata.h | 7 ++
3 files changed, 286 insertions(+), 9 deletions(-)
240ed4c86ceaf789e40f638a63402d60e7c0555c
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index ba9f346..0ee7ab4 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -70,6 +70,7 @@ static unsigned int ata_dev_init_params(
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
+static int ata_host_set_resume(struct ata_host_set *host_set);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
@@ -4950,6 +4951,104 @@ int ata_port_offline(struct ata_port *ap
return 0;
}
+static void ata_host_set_request_pm(struct ata_host_set *host_set,
+ pm_message_t mesg)
+{
+ int i;
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
+ unsigned long flags;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ while (ap->flags & ATA_FLAG_PM_PENDING) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ ata_port_wait_eh(ap);
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ }
+
+ /* request PM ops to EH */
+ ap->flags |= ATA_FLAG_PM_PENDING;
+ ap->pm_mesg = mesg;
+ ap->pm_result = 0;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ }
+}
+
+static int ata_host_set_wait_pm(struct ata_host_set *host_set)
+{
+ int i, rc = 0;
+
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
+
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->flags & ATA_FLAG_PM_PENDING);
+
+ if (ap->pm_result)
+ rc = ap->pm_result;
+ }
+
+ return rc;
+}
+
+/**
+ * ata_host_set_suspend - suspend host_set
+ * @host_set: host_set to suspend
+ * @mesg: PM message
+ *
+ * Suspend @host_set. 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.
+ */
+static int ata_host_set_suspend(struct ata_host_set *host_set,
+ pm_message_t mesg)
+{
+ int rc;
+
+ ata_host_set_request_pm(host_set, mesg);
+ rc = ata_host_set_wait_pm(host_set);
+
+ host_set->dev->power.power_state = mesg;
+ if (rc)
+ ata_host_set_resume(host_set);
+
+ return rc;
+}
+
+/**
+ * ata_host_set_resume - resume host_set
+ * @host_set: host_set to resume
+ *
+ * Resume @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and returns.
+ * Note that all resume operations are performed parallely.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0.
+ */
+static int ata_host_set_resume(struct ata_host_set *host_set)
+{
+ ata_host_set_request_pm(host_set, PMSG_ON);
+ host_set->dev->power.power_state = PMSG_ON;
+ return 0;
+}
+
/**
* ata_port_start - Set port up for dma.
* @ap: Port to initialize
@@ -5584,22 +5683,51 @@ int pci_test_config_bits(struct pci_dev
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
{
- pci_save_state(pdev);
- pci_disable_device(pdev);
+ struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
+ struct ata_host_set *host_set;
+ int rc = 0;
+
+ for (host_set = first_hset; host_set; host_set = host_set->next) {
+ rc = ata_host_set_suspend(host_set, state);
+ if (rc)
+ break;
+ }
- if (state.event == PM_EVENT_SUSPEND)
- pci_set_power_state(pdev, PCI_D3hot);
+ if (rc == 0) {
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
- return 0;
+ if (state.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ /* Resume the first host_set too if the second one
+ * failed to sleep.
+ */
+ if (host_set != first_hset)
+ ata_host_set_resume(first_hset);
+ }
+
+ return rc;
}
int ata_pci_device_resume(struct pci_dev *pdev)
{
+ struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
+ struct ata_host_set *host_set;
+ int tmp, rc = 0;
+
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_device(pdev);
pci_set_master(pdev);
- return 0;
+
+ for (host_set = first_hset; host_set; host_set = host_set->next) {
+ tmp = ata_host_set_resume(host_set);
+ if (tmp)
+ rc = tmp;
+ }
+
+ return rc;
}
#endif /* CONFIG_PCI */
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 8711e83..6191964 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -47,6 +47,8 @@ #include "libata.h"
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_suspend(struct ata_port *ap);
+static void ata_eh_handle_resume(struct ata_port *ap);
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@@ -243,10 +245,14 @@ void ata_scsi_error(struct Scsi_Host *ho
spin_unlock_irqrestore(hs_lock, flags);
- /* invoke EH. if unloading, just finish failed qcs */
- if (!(ap->flags & ATA_FLAG_UNLOADING))
+ /* invoke EH, skip if unloading or suspended */
+ if (!(ap->flags & ATA_FLAG_UNLOADING) &&
+ (!(ap->flags & ATA_FLAG_SUSPENDED) ||
+ ap->flags & ATA_FLAG_PM_PENDING)) {
+ ata_eh_handle_resume(ap);
ap->ops->error_handler(ap);
- else
+ ata_eh_handle_suspend(ap);
+ } else
ata_eh_finish(ap);
/* Exception might have happend after ->error_handler
@@ -1889,3 +1895,139 @@ void ata_do_eh(struct ata_port *ap, ata_
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
+
+static int ata_flush_cache(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ u8 cmd;
+
+ if (!ata_try_flush_cache(dev))
+ return 0;
+
+ if (ata_id_has_flush_ext(dev->id))
+ cmd = ATA_CMD_FLUSH_EXT;
+ else
+ cmd = ATA_CMD_FLUSH;
+
+ err_mask = ata_do_simple_cmd(dev, cmd);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_eh_handle_suspend - perform suspend operation
+ * @ap: port to suspend
+ *
+ * Suspend @ap. All disk devices on @ap will be flushed and put
+ * into standby mode, the port is frozen and LLD is given a
+ * chance to tidy things up.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_suspend(struct ata_port *ap)
+{
+ int do_suspend = ap->pm_mesg.event == PM_EVENT_SUSPEND;
+ unsigned long flags;
+ int i, rc;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
+ ap->pm_mesg.event == PM_EVENT_ON) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return;
+ }
+ ap->flags &= ~ATA_FLAG_PM_PENDING;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ if (do_suspend) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int err_mask;
+
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+
+ /* flush cache */
+ rc = ata_flush_cache(dev);
+ if (rc)
+ goto fail;
+
+ /* spin down */
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to spin down (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ goto fail;
+ }
+ }
+ }
+
+ ata_eh_freeze_port(ap);
+
+ if (ap->ops->suspend) {
+ rc = ap->ops->suspend(ap, ap->pm_mesg);
+ if (rc)
+ goto fail;
+ }
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags |= ATA_FLAG_SUSPENDED;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return;
+
+ fail:
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ata_port_schedule_eh(ap);
+ ap->pm_result = rc;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
+/**
+ * ata_eh_handle_resume - perform resume operation
+ * @ap: port to resume
+ *
+ * Resume @ap. For all devices on @ap, SPINUP EH action and
+ * hotplug handling are requested. LLD is given a chance to wake
+ * @ap up before EH takes over and performs those operations.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_resume(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
+ !(ap->flags & ATA_FLAG_SUSPENDED) ||
+ ap->pm_mesg.event != PM_EVENT_ON) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return;
+ }
+ ap->flags &= ~ATA_FLAG_PM_PENDING;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ struct ata_eh_context *ehc = &ap->eh_context;
+
+ ehc->i.action |= ATA_EH_SPINUP;
+ ata_ehi_hotplugged(&ehc->i);
+ }
+
+ if (ap->ops->resume)
+ rc = ap->ops->resume(ap);
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags &= ~ATA_FLAG_SUSPENDED;
+ ap->pm_result = rc;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e5ff148..267f3d8 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -172,6 +172,7 @@ enum {
ATA_FLAG_DISABLED = (1 << 21), /* port is disabled, ignore it */
ATA_FLAG_SUSPENDED = (1 << 22), /* port is suspended (power) */
+ ATA_FLAG_PM_PENDING = (1 << 23), /* PM event pending */
/* bits 24:31 of ap->flags are reserved for LLDD specific flags */
@@ -531,6 +532,9 @@ struct ata_port {
struct list_head eh_done_q;
wait_queue_head_t eh_wait_q;
+ pm_message_t pm_mesg;
+ int pm_result;
+
void *private_data;
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -585,6 +589,9 @@ struct ata_port_operations {
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
+ int (*suspend) (struct ata_port *ap, pm_message_t mesg);
+ int (*resume) (struct ata_port *ap);
+
int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap);
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (7 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 07/10] sata_sil: separate out sil_init_controller() Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-14 1:18 ` Jeff Garzik
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
` (4 subsequent siblings)
13 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Implement new EH action ATA_EH_SPINUP. This will be used by new PM
implementation.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-eh.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/libata.h | 1 +
2 files changed, 37 insertions(+), 0 deletions(-)
c0a5ccaf24b0acc3e03c4b265ef6495db36623ae
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 531a4e1..8711e83 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1585,6 +1585,37 @@ static int ata_eh_revalidate_and_attach(
return rc;
}
+static int ata_eh_spinup(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev;
+ unsigned int err_mask = 0;
+ int i;
+
+ if (!(ehc->i.action & ATA_EH_SPINUP))
+ return 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+
+ ata_eh_about_to_do(ap, ATA_EH_SPINUP);
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+ if (err_mask)
+ break;
+ }
+
+ if (err_mask == 0) {
+ ehc->i.action &= ~ATA_EH_SPINUP;
+ return 0;
+ } else {
+ *r_failed_dev = dev;
+ return -EIO;
+ }
+}
+
static int ata_port_nr_enabled(struct ata_port *ap)
{
int i, cnt = 0;
@@ -1711,6 +1742,11 @@ static int ata_eh_recover(struct ata_por
if (rc)
goto dev_fail;
+ /* spin up if requested */
+ rc = ata_eh_spinup(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
/* configure transfer mode if the port has been reset */
if (ehc->i.flags & ATA_EHI_DID_RESET) {
rc = ata_set_mode(ap, &dev);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 17c8ced..e5ff148 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -246,6 +246,7 @@ enum {
ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2),
+ ATA_EH_SPINUP = (1 << 3),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH 08/10] sata_sil: add suspend/sleep support
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (5 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 10/10] sata_sil24: add suspend/sleep support Tejun Heo
@ 2006-06-12 15:50 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 07/10] sata_sil: separate out sil_init_controller() Tejun Heo
` (6 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:50 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide; +Cc: Tejun Heo
Add suspend/sleep support.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/sata_sil.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
cfac09b587dd3913ebf3f75766a57559e75de672
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 4bff260..bb63db2 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -107,6 +107,7 @@ enum {
};
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -158,6 +159,8 @@ static struct pci_driver sil_pci_driver
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = sil_pci_device_resume,
};
static struct scsi_host_template sil_sht = {
@@ -660,6 +663,16 @@ err_out:
return rc;
}
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+ sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
+ host_set->mmio_base);
+
+ return ata_pci_device_resume(pdev);
+}
+
static int __init sil_init(void)
{
return pci_module_init(&sil_pci_driver);
--
1.3.2
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [PATCHSET] new Power Management for libata
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (9 preceding siblings ...)
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
@ 2006-06-12 15:57 ` Tejun Heo
2006-06-13 6:28 ` zhao, forrest
` (2 subsequent siblings)
13 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-12 15:57 UTC (permalink / raw)
To: jgarzik; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
This patchset is available at the following git tree.
http://htj.dyndns.org/git/?p=libata-tj.git;a=shortlog;h=new-pm
git://htj.dyndns.org/libata-tj new-pm
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND
2006-06-12 15:50 ` [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND Tejun Heo
@ 2006-06-12 16:32 ` Jeff Garzik
2006-06-13 2:20 ` Tejun Heo
0 siblings, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2006-06-12 16:32 UTC (permalink / raw)
To: Tejun Heo; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
Tejun Heo wrote:
> The controller only needs to be powered down on PMSG_SUSPEND. Skip
> powering down for all other messages. This makes disk suspend prep
> cycle more efficient and helps controllers which have problems waking
> up from D3hot without intervening power removal.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
>
> ---
>
> drivers/scsi/libata-core.c | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
>
> 85016ad86323924d10dc99ac9d7e9e5c0b967b8e
> diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
> index 9a3bd15..51d3b4b 100644
> --- a/drivers/scsi/libata-core.c
> +++ b/drivers/scsi/libata-core.c
> @@ -5661,7 +5661,10 @@ int ata_pci_device_suspend(struct pci_de
> {
> pci_save_state(pdev);
> pci_disable_device(pdev);
> - pci_set_power_state(pdev, PCI_D3hot);
> +
> + if (state.event == PM_EVENT_SUSPEND)
> + pci_set_power_state(pdev, PCI_D3hot);
If this change makes sense for the D0->D3 transition, surely it would
make sense to cover the other operations (save-state, disable) as well?
Jeff
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
@ 2006-06-12 16:34 ` Alan Cox
2006-06-13 2:08 ` Tejun Heo
2006-06-13 6:25 ` zhao, forrest
` (3 subsequent siblings)
4 siblings, 1 reply; 39+ messages in thread
From: Alan Cox @ 2006-06-12 16:34 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, forrest.zhao, linux-ide
Ar Maw, 2006-06-13 am 00:50 +0900, ysgrifennodd Tejun Heo:
> Suspend is performed parallely on all ports of a host_set and resume
> is done parallely in background to decrease the time necessary before
> responding to user.
Do we need a disk count here - some large disk setups rely on the fact
drives don't all spin up at once to avoid overloading the PSU ?
Something like four disk spinups at a time ought to avoid biting anyone
too badly and would mean normal users saw a parallel spinup.
Alan
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 16:34 ` Alan Cox
@ 2006-06-13 2:08 ` Tejun Heo
0 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-13 2:08 UTC (permalink / raw)
To: Alan Cox; +Cc: jgarzik, lkml, axboe, forrest.zhao, linux-ide
Alan Cox wrote:
> Ar Maw, 2006-06-13 am 00:50 +0900, ysgrifennodd Tejun Heo:
>> Suspend is performed parallely on all ports of a host_set and resume
>> is done parallely in background to decrease the time necessary before
>> responding to user.
>
> Do we need a disk count here - some large disk setups rely on the fact
> drives don't all spin up at once to avoid overloading the PSU ?
For most desktops and notebooks, it doesn't really matter as power is
removed from disks during memsleep and they all spin up immediately
after resume regardless of what libata does. For external enclosures
with separate power supply, limiting the number of concurrent spinups
during resume is necessary though.
I think we need to make a central disk spinup limiter to control the
number of concurrent spinups across both ATA and SCSI. SATA staggered
spinup should be considered too. Depending on situation, a drive may
spin up on power up, PHY ready or IDLE_IMM after resuming from memsleep.
FWIW, my cheapo 325w PSU (< 30USD) hasn't had any problem spinning up 11
drives simultaneously.
I think it's okay to leave it as it is for the time being. It's not
like people w/ external enclosures use suspend/resume a lot.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND
2006-06-12 16:32 ` Jeff Garzik
@ 2006-06-13 2:20 ` Tejun Heo
0 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-13 2:20 UTC (permalink / raw)
To: Jeff Garzik; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
Jeff Garzik wrote:
> Tejun Heo wrote:
>> The controller only needs to be powered down on PMSG_SUSPEND. Skip
>> powering down for all other messages. This makes disk suspend prep
>> cycle more efficient and helps controllers which have problems waking
>> up from D3hot without intervening power removal.
>>
>> Signed-off-by: Tejun Heo <htejun@gmail.com>
>>
>> ---
>>
>> drivers/scsi/libata-core.c | 5 ++++-
>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>
>> 85016ad86323924d10dc99ac9d7e9e5c0b967b8e
>> diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
>> index 9a3bd15..51d3b4b 100644
>> --- a/drivers/scsi/libata-core.c
>> +++ b/drivers/scsi/libata-core.c
>> @@ -5661,7 +5661,10 @@ int ata_pci_device_suspend(struct pci_de
>> {
>> pci_save_state(pdev);
>> pci_disable_device(pdev);
>> - pci_set_power_state(pdev, PCI_D3hot);
>> +
>> + if (state.event == PM_EVENT_SUSPEND)
>> + pci_set_power_state(pdev, PCI_D3hot);
>
> If this change makes sense for the D0->D3 transition, surely it would
> make sense to cover the other operations (save-state, disable) as well?
It probably makes sense for disable but not for save-state. Swsusp
takes snapshot of memory after freezing all devices and resumes again to
write the snapshot. Resume must be able to reinitialize the hardware
from scratch and it depends on PCI config regs saved w/
pci_save_state(). So, state must be saved during freeze.
I'll put pci_disable_device() in the if clause and retest. That should
work.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
2006-06-12 16:34 ` Alan Cox
@ 2006-06-13 6:25 ` zhao, forrest
2006-06-13 8:56 ` Tejun Heo
2006-06-13 8:17 ` zhao, forrest
` (2 subsequent siblings)
4 siblings, 1 reply; 39+ messages in thread
From: zhao, forrest @ 2006-06-13 6:25 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
> @@ -5584,22 +5683,51 @@ int pci_test_config_bits(struct pci_dev
>
> int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
> {
> - pci_save_state(pdev);
> - pci_disable_device(pdev);
> + struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
> + struct ata_host_set *host_set;
> + int rc = 0;
> +
> + for (host_set = first_hset; host_set; host_set = host_set->next) {
> + rc = ata_host_set_suspend(host_set, state);
> + if (rc)
> + break;
> + }
My original understanding is that a host_set represents a physical SATA
controller in a PCI slot. In which case will a SATA controller include
multiple host_set?
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCHSET] new Power Management for libata
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (10 preceding siblings ...)
2006-06-12 15:57 ` [PATCHSET] new Power Management for libata Tejun Heo
@ 2006-06-13 6:28 ` zhao, forrest
2006-06-13 9:09 ` rolled up patch for " Tejun Heo
2006-06-14 1:25 ` [PATCHSET] " Jeff Garzik
13 siblings, 0 replies; 39+ messages in thread
From: zhao, forrest @ 2006-06-13 6:28 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
> Zhao, can you port your AHCI PM stuff over this? This should solve
> the problem you talked about in the other mail. Recent changes update
> ahci such that it listens to more PHY events for hotplug and that
> causes EH to kick in after resuming. The original PM implementation
> didn't synchronize w/ EH and thus caused problems.
>
I'm doing the porting work, but not sure if I should send out patch
ASAP, or not send it out until your PM patches are merged into
#upstream.
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
2006-06-12 16:34 ` Alan Cox
2006-06-13 6:25 ` zhao, forrest
@ 2006-06-13 8:17 ` zhao, forrest
2006-06-13 9:00 ` Tejun Heo
2006-06-13 8:37 ` zhao, forrest
2006-06-14 7:56 ` zhao, forrest
4 siblings, 1 reply; 39+ messages in thread
From: zhao, forrest @ 2006-06-13 8:17 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
> int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
> {
> - pci_save_state(pdev);
> - pci_disable_device(pdev);
> + struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
> + struct ata_host_set *host_set;
> + int rc = 0;
> +
> + for (host_set = first_hset; host_set; host_set = host_set->next) {
> + rc = ata_host_set_suspend(host_set, state);
> + if (rc)
> + break;
> + }
>
> - if (state.event == PM_EVENT_SUSPEND)
> - pci_set_power_state(pdev, PCI_D3hot);
> + if (rc == 0) {
> + pci_save_state(pdev);
> + pci_disable_device(pdev);
>
> - return 0;
> + if (state.event == PM_EVENT_SUSPEND)
> + pci_set_power_state(pdev, PCI_D3hot);
> + } else {
> + /* Resume the first host_set too if the second one
> + * failed to sleep.
> + */
> + if (host_set != first_hset)
> + ata_host_set_resume(first_hset);
> + }
> +
> + return rc;
> }
Is it possible to add a callback in ata_pci_device_suspend() to do
controller-level operation before calling pci_save_state()......?
One possible solution is to put this callback into a structure together
with host_set.
Otherwise user-defined ahci_pci_device_suspend() will duplicate most
code of ata_pci_device_suspend().
Thanks,
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
` (2 preceding siblings ...)
2006-06-13 8:17 ` zhao, forrest
@ 2006-06-13 8:37 ` zhao, forrest
2006-06-14 7:56 ` zhao, forrest
4 siblings, 0 replies; 39+ messages in thread
From: zhao, forrest @ 2006-06-13 8:37 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
>
> int ata_pci_device_resume(struct pci_dev *pdev)
> {
> + struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
> + struct ata_host_set *host_set;
> + int tmp, rc = 0;
> +
> pci_set_power_state(pdev, PCI_D0);
> pci_restore_state(pdev);
> pci_enable_device(pdev);
> pci_set_master(pdev);
> - return 0;
> +
> + for (host_set = first_hset; host_set; host_set = host_set->next) {
> + tmp = ata_host_set_resume(host_set);
> + if (tmp)
> + rc = tmp;
> + }
> +
> + return rc;
> }
> #endif /* CONFIG_PCI */
Similar here. Is it possible to introduce two controller-level
callbacks, say ->pre_resume(), which is called before
pci_set_power_state(), ->post_resume(), which is called after for()
loop? This is needed by AHCI resume. Otherwise most code of
ata_pci_device_resume() will be duplicated in ahci_pci_device_resume().
Another point is for AHCI resume we need to wait the resume operation of
all ports to complete before calling ->post_resume().
Thanks,
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-13 9:00 ` Tejun Heo
@ 2006-06-13 8:54 ` zhao, forrest
2006-06-13 9:15 ` Tejun Heo
0 siblings, 1 reply; 39+ messages in thread
From: zhao, forrest @ 2006-06-13 8:54 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Tue, 2006-06-13 at 18:00 +0900, Tejun Heo wrote:
> If ata_pci_device_suspend/resume() do things incorrect for a
> controller(), export ata_host_set_suspend/resume() and call those from
> LLD's suspend/resume() routines.
>
OK. I'll export them in the upcoming AHCI suspend/resume patches.
Thanks,
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-13 6:25 ` zhao, forrest
@ 2006-06-13 8:56 ` Tejun Heo
2006-06-13 11:59 ` Jeff Garzik
0 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-13 8:56 UTC (permalink / raw)
To: zhao, forrest; +Cc: jgarzik, lkml, axboe, alan, linux-ide
zhao, forrest wrote:
> On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
>> @@ -5584,22 +5683,51 @@ int pci_test_config_bits(struct pci_dev
>>
>> int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
>> {
>> - pci_save_state(pdev);
>> - pci_disable_device(pdev);
>> + struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
>> + struct ata_host_set *host_set;
>> + int rc = 0;
>> +
>> + for (host_set = first_hset; host_set; host_set = host_set->next) {
>> + rc = ata_host_set_suspend(host_set, state);
>> + if (rc)
>> + break;
>> + }
>
> My original understanding is that a host_set represents a physical SATA
> controller in a PCI slot. In which case will a SATA controller include
> multiple host_set?
Please read ata_pci_init_one() and ata_pci_init_legacy_port() in
libata-bmdma.c. It's for IDE controllers in legacy mode (not native
PCI) mode.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-13 8:17 ` zhao, forrest
@ 2006-06-13 9:00 ` Tejun Heo
2006-06-13 8:54 ` zhao, forrest
0 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-13 9:00 UTC (permalink / raw)
To: zhao, forrest; +Cc: jgarzik, lkml, axboe, alan, linux-ide
zhao, forrest wrote:
> Is it possible to add a callback in ata_pci_device_suspend() to do
> controller-level operation before calling pci_save_state()......?
> One possible solution is to put this callback into a structure together
> with host_set.
> Otherwise user-defined ahci_pci_device_suspend() will duplicate most
> code of ata_pci_device_suspend().
If a LLD wants to do controller specific things, define its own
device_suspend/resume() routines and call ata_pci_device_*() from those
functions after doing controller-specific stuff. Please read how
sil_pci_device_resume() and sil24_pci_device_resume() are defined later
in this patchset.
If ata_pci_device_suspend/resume() do things incorrect for a
controller(), export ata_host_set_suspend/resume() and call those from
LLD's suspend/resume() routines.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* rolled up patch for new Power Management for libata
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (11 preceding siblings ...)
2006-06-13 6:28 ` zhao, forrest
@ 2006-06-13 9:09 ` Tejun Heo
2006-06-13 10:38 ` Jens Axboe
2006-06-14 1:25 ` [PATCHSET] " Jeff Garzik
13 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-13 9:09 UTC (permalink / raw)
To: jgarzik, lkml, axboe, forrest.zhao, alan, linux-ide
This is a rolled up version of new-pm patchset for testing as
requested by Jens.
This patch is against
libata-dev #upstream (aeb2ecd6096182cc080d37679080c0f088dcd4a4)
And contains the following patches
upstream (aeb2ecd6096182cc080d37679080c0f088dcd4a4)
+ [1] kill-ATA_FLAG_SRST patch
+ [2] shift-ATA_FLAG_-bits patch
+ [3] new-power-management-for-libata patchset
[1] http://marc.theaimsgroup.com/?l=linux-ide&m=115012501502940&w=2
[2] http://marc.theaimsgroup.com/?l=linux-ide&m=115012349728574&w=2
[3] http://marc.theaimsgroup.com/?l=linux-ide&m=115012753926326&w=2
The git tree containing these changes can be accessed at the following URL.
http://htj.dyndns.org/git/?p=libata-tj.git;a=shortlog;h=new-pm
git://htj.dyndns.org/libata-tj new-pm
Patch follows...
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 521b718..75aa47f 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -220,8 +220,6 @@ static struct scsi_host_template piix_sh
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
- .resume = ata_scsi_device_resume,
- .suspend = ata_scsi_device_suspend,
};
static const struct ata_port_operations piix_pata_ops = {
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 4bc0537..13fab97 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -1076,10 +1076,21 @@ int ata_pci_init_one (struct pci_dev *pd
/* FIXME: check ata_device_add return */
if (legacy_mode) {
- if (legacy_mode & (1 << 0))
+ struct device *dev = &pdev->dev;
+ struct ata_host_set *host_set = NULL;
+
+ if (legacy_mode & (1 << 0)) {
ata_device_add(probe_ent);
- if (legacy_mode & (1 << 1))
+ host_set = dev_get_drvdata(dev);
+ }
+
+ if (legacy_mode & (1 << 1)) {
ata_device_add(probe_ent2);
+ if (host_set) {
+ host_set->next = dev_get_drvdata(dev);
+ dev_set_drvdata(dev, host_set);
+ }
+ }
} else
ata_device_add(probe_ent);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 014855e..0ee7ab4 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -70,6 +70,7 @@ static unsigned int ata_dev_init_params(
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
+static int ata_host_set_resume(struct ata_host_set *host_set);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
@@ -1123,6 +1124,32 @@ unsigned ata_exec_internal(struct ata_de
return err_mask;
}
+/* ata_do_simple_cmd - execute simple internal command
+ * @dev: Device to which the command is sent
+ * @cmd: Opcode to execute
+ *
+ * Execute a 'simple' command, that only consists of the opcode
+ * 'cmd' itself, without filling any other registers
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
+ */
+unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+{
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = cmd;
+ tf.flags |= ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+}
+
/**
* ata_pio_need_iordy - check if iordy needed
* @adev: ATA device
@@ -2380,7 +2407,7 @@ void ata_bus_reset(struct ata_port *ap)
ap->ops->dev_select(ap, 0);
/* issue bus reset */
- if (ap->flags & ATA_FLAG_SRST)
+ if (!(ap->flags & ATA_FLAG_SATA_RESET))
if (ata_bus_softreset(ap, devmask))
goto err_out;
@@ -2406,13 +2433,11 @@ void ata_bus_reset(struct ata_port *ap)
(ap->device[1].class == ATA_DEV_NONE))
goto err_out;
- if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
- /* set up device control for ATA_FLAG_SATA_RESET */
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
- }
+ /* set up device control for ATA_FLAG_SATA_RESET */
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+ else
+ outb(ap->ctl, ioaddr->ctl_addr);
DPRINTK("EXIT\n");
return;
@@ -4926,104 +4951,101 @@ int ata_port_offline(struct ata_port *ap
return 0;
}
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
- */
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+static void ata_host_set_request_pm(struct ata_host_set *host_set,
+ pm_message_t mesg)
{
- struct ata_taskfile tf;
- int err;
+ int i;
- ata_tf_init(dev, &tf);
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
+ unsigned long flags;
- tf.command = cmd;
- tf.flags |= ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
+ spin_lock_irqsave(&ap->host_set->lock, flags);
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
- __FUNCTION__, err);
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ while (ap->flags & ATA_FLAG_PM_PENDING) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ ata_port_wait_eh(ap);
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ }
+
+ /* request PM ops to EH */
+ ap->flags |= ATA_FLAG_PM_PENDING;
+ ap->pm_mesg = mesg;
+ ap->pm_result = 0;
+ ata_port_schedule_eh(ap);
- return err;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ }
}
-static int ata_flush_cache(struct ata_device *dev)
+static int ata_host_set_wait_pm(struct ata_host_set *host_set)
{
- u8 cmd;
+ int i, rc = 0;
- if (!ata_try_flush_cache(dev))
- return 0;
-
- if (ata_id_has_flush_ext(dev->id))
- cmd = ATA_CMD_FLUSH_EXT;
- else
- cmd = ATA_CMD_FLUSH;
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
- return ata_do_simple_cmd(dev, cmd);
-}
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->flags & ATA_FLAG_PM_PENDING);
-static int ata_standby_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
-}
+ if (ap->pm_result)
+ rc = ap->pm_result;
+ }
-static int ata_start_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+ return rc;
}
/**
- * ata_device_resume - wakeup a previously suspended devices
- * @dev: the device to resume
+ * ata_host_set_suspend - suspend host_set
+ * @host_set: host_set to suspend
+ * @mesg: PM message
+ *
+ * Suspend @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and waits for EH
+ * to finish.
*
- * Kick the drive back into action, by sending it an idle immediate
- * command and making sure its transfer mode matches between drive
- * and host.
+ * LOCKING:
+ * Kernel thread context (may sleep).
*
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-int ata_device_resume(struct ata_device *dev)
+static int ata_host_set_suspend(struct ata_host_set *host_set,
+ pm_message_t mesg)
{
- struct ata_port *ap = dev->ap;
-
- if (ap->flags & ATA_FLAG_SUSPENDED) {
- struct ata_device *failed_dev;
+ int rc;
- ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+ ata_host_set_request_pm(host_set, mesg);
+ rc = ata_host_set_wait_pm(host_set);
- ap->flags &= ~ATA_FLAG_SUSPENDED;
- while (ata_set_mode(ap, &failed_dev))
- ata_dev_disable(failed_dev);
- }
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_start_drive(dev);
+ host_set->dev->power.power_state = mesg;
+ if (rc)
+ ata_host_set_resume(host_set);
- return 0;
+ return rc;
}
/**
- * ata_device_suspend - prepare a device for suspend
- * @dev: the device to suspend
- * @state: target power management state
+ * ata_host_set_resume - resume host_set
+ * @host_set: host_set to resume
*
- * Flush the cache on the drive, if appropriate, then issue a
- * standbynow command.
+ * Resume @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and returns.
+ * Note that all resume operations are performed parallely.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0.
*/
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
+static int ata_host_set_resume(struct ata_host_set *host_set)
{
- struct ata_port *ap = dev->ap;
-
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(dev);
-
- if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(dev);
- ap->flags |= ATA_FLAG_SUSPENDED;
+ ata_host_set_request_pm(host_set, PMSG_ON);
+ host_set->dev->power.power_state = PMSG_ON;
return 0;
}
@@ -5245,13 +5267,6 @@ static struct ata_port * ata_host_add(co
DPRINTK("ENTER\n");
- if (!ent->port_ops->error_handler &&
- !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
- printk(KERN_ERR "ata%u: no reset mechanism available\n",
- port_no);
- return NULL;
- }
-
host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
if (!host)
return NULL;
@@ -5621,8 +5636,12 @@ void ata_pci_remove_one (struct pci_dev
{
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host_set *host_set = dev_get_drvdata(dev);
+ struct ata_host_set *host_set2 = host_set->next;
ata_host_set_remove(host_set);
+ if (host_set2)
+ ata_host_set_remove(host_set2);
+
pci_release_regions(pdev);
pci_disable_device(pdev);
dev_set_drvdata(dev, NULL);
@@ -5664,19 +5683,51 @@ int pci_test_config_bits(struct pci_dev
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
{
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
- return 0;
+ struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
+ struct ata_host_set *host_set;
+ int rc = 0;
+
+ for (host_set = first_hset; host_set; host_set = host_set->next) {
+ rc = ata_host_set_suspend(host_set, state);
+ if (rc)
+ break;
+ }
+
+ if (rc == 0) {
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (state.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ /* Resume the first host_set too if the second one
+ * failed to sleep.
+ */
+ if (host_set != first_hset)
+ ata_host_set_resume(first_hset);
+ }
+
+ return rc;
}
int ata_pci_device_resume(struct pci_dev *pdev)
{
+ struct ata_host_set *first_hset = dev_get_drvdata(&pdev->dev);
+ struct ata_host_set *host_set;
+ int tmp, rc = 0;
+
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_device(pdev);
pci_set_master(pdev);
- return 0;
+
+ for (host_set = first_hset; host_set; host_set = host_set->next) {
+ tmp = ata_host_set_resume(host_set);
+ if (tmp)
+ rc = tmp;
+ }
+
+ return rc;
}
#endif /* CONFIG_PCI */
@@ -5874,11 +5925,6 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
-EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
-EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
-
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_port_abort);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 531a4e1..6191964 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -47,6 +47,8 @@ #include "libata.h"
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_suspend(struct ata_port *ap);
+static void ata_eh_handle_resume(struct ata_port *ap);
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@@ -243,10 +245,14 @@ void ata_scsi_error(struct Scsi_Host *ho
spin_unlock_irqrestore(hs_lock, flags);
- /* invoke EH. if unloading, just finish failed qcs */
- if (!(ap->flags & ATA_FLAG_UNLOADING))
+ /* invoke EH, skip if unloading or suspended */
+ if (!(ap->flags & ATA_FLAG_UNLOADING) &&
+ (!(ap->flags & ATA_FLAG_SUSPENDED) ||
+ ap->flags & ATA_FLAG_PM_PENDING)) {
+ ata_eh_handle_resume(ap);
ap->ops->error_handler(ap);
- else
+ ata_eh_handle_suspend(ap);
+ } else
ata_eh_finish(ap);
/* Exception might have happend after ->error_handler
@@ -1585,6 +1591,37 @@ static int ata_eh_revalidate_and_attach(
return rc;
}
+static int ata_eh_spinup(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev;
+ unsigned int err_mask = 0;
+ int i;
+
+ if (!(ehc->i.action & ATA_EH_SPINUP))
+ return 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+
+ ata_eh_about_to_do(ap, ATA_EH_SPINUP);
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+ if (err_mask)
+ break;
+ }
+
+ if (err_mask == 0) {
+ ehc->i.action &= ~ATA_EH_SPINUP;
+ return 0;
+ } else {
+ *r_failed_dev = dev;
+ return -EIO;
+ }
+}
+
static int ata_port_nr_enabled(struct ata_port *ap)
{
int i, cnt = 0;
@@ -1711,6 +1748,11 @@ static int ata_eh_recover(struct ata_por
if (rc)
goto dev_fail;
+ /* spin up if requested */
+ rc = ata_eh_spinup(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
/* configure transfer mode if the port has been reset */
if (ehc->i.flags & ATA_EHI_DID_RESET) {
rc = ata_set_mode(ap, &dev);
@@ -1853,3 +1895,139 @@ void ata_do_eh(struct ata_port *ap, ata_
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
+
+static int ata_flush_cache(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ u8 cmd;
+
+ if (!ata_try_flush_cache(dev))
+ return 0;
+
+ if (ata_id_has_flush_ext(dev->id))
+ cmd = ATA_CMD_FLUSH_EXT;
+ else
+ cmd = ATA_CMD_FLUSH;
+
+ err_mask = ata_do_simple_cmd(dev, cmd);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_eh_handle_suspend - perform suspend operation
+ * @ap: port to suspend
+ *
+ * Suspend @ap. All disk devices on @ap will be flushed and put
+ * into standby mode, the port is frozen and LLD is given a
+ * chance to tidy things up.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_suspend(struct ata_port *ap)
+{
+ int do_suspend = ap->pm_mesg.event == PM_EVENT_SUSPEND;
+ unsigned long flags;
+ int i, rc;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
+ ap->pm_mesg.event == PM_EVENT_ON) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return;
+ }
+ ap->flags &= ~ATA_FLAG_PM_PENDING;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ if (do_suspend) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int err_mask;
+
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+
+ /* flush cache */
+ rc = ata_flush_cache(dev);
+ if (rc)
+ goto fail;
+
+ /* spin down */
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to spin down (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ goto fail;
+ }
+ }
+ }
+
+ ata_eh_freeze_port(ap);
+
+ if (ap->ops->suspend) {
+ rc = ap->ops->suspend(ap, ap->pm_mesg);
+ if (rc)
+ goto fail;
+ }
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags |= ATA_FLAG_SUSPENDED;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return;
+
+ fail:
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ata_port_schedule_eh(ap);
+ ap->pm_result = rc;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
+/**
+ * ata_eh_handle_resume - perform resume operation
+ * @ap: port to resume
+ *
+ * Resume @ap. For all devices on @ap, SPINUP EH action and
+ * hotplug handling are requested. LLD is given a chance to wake
+ * @ap up before EH takes over and performs those operations.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_resume(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
+ !(ap->flags & ATA_FLAG_SUSPENDED) ||
+ ap->pm_mesg.event != PM_EVENT_ON) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return;
+ }
+ ap->flags &= ~ATA_FLAG_PM_PENDING;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ struct ata_eh_context *ehc = &ap->eh_context;
+
+ ehc->i.action |= ATA_EH_SPINUP;
+ ata_ehi_hotplugged(&ehc->i);
+ }
+
+ if (ap->ops->resume)
+ rc = ap->ops->resume(ap);
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags &= ~ATA_FLAG_SUSPENDED;
+ ap->pm_result = rc;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 45a49be..0c30e6c 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -399,22 +399,6 @@ void ata_dump_status(unsigned id, struct
}
}
-int ata_scsi_device_resume(struct scsi_device *sdev)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- return ata_device_resume(dev);
-}
-
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- return ata_device_suspend(dev, state);
-}
-
/**
* ata_to_sense_error - convert ATA error to SCSI error
* @id: ATA device number
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index bdd4888..539b0b5 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -50,6 +50,7 @@ extern void ata_port_flush_task(struct a
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen);
+extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
int post_reset, u16 *id);
extern int ata_dev_configure(struct ata_device *dev, int print_info);
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index 7ebe8e0..3831858 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -182,8 +182,8 @@ static struct ata_port_info adma_port_in
/* board_1841_idx */
{
.sht = &adma_ata_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
- ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO,
+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
.pio_mask = 0x10, /* pio4 */
.udma_mask = 0x1f, /* udma0-4 */
.port_ops = &adma_ata_ops,
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 9055124..aa69753 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -257,7 +257,6 @@ static struct ata_port_info nv_port_info
.sht = &nv_sht,
.host_flags = ATA_FLAG_SATA |
/* ATA_FLAG_SATA_RESET | */
- ATA_FLAG_SRST |
ATA_FLAG_NO_LEGACY,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index b2b6ed5..083e06e 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -75,9 +75,8 @@ enum {
PDC_RESET = (1 << 11), /* HDMA reset */
- PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
- ATA_FLAG_PIO_POLLING,
+ PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
+ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
};
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 98ddc25..5c84b06 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -176,7 +176,6 @@ static const struct ata_port_info qs_por
.sht = &qs_ata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
- //FIXME ATA_FLAG_SRST |
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
.udma_mask = 0x7f, /* udma0-6 */
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index a7e99a1..bb63db2 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -107,6 +107,7 @@ enum {
};
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -158,6 +159,8 @@ static struct pci_driver sil_pci_driver
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = sil_pci_device_resume,
};
static struct scsi_host_template sil_sht = {
@@ -526,6 +529,52 @@ static void sil_dev_config(struct ata_po
}
}
+static void sil_init_controller(struct pci_dev *pdev,
+ int n_ports, unsigned long host_flags,
+ void __iomem *mmio_base)
+{
+ u8 cls;
+ u32 tmp;
+ int i;
+
+ /* Initialize FIFO PCI bus arbitration */
+ cls = sil_get_device_cache_line(pdev);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ for (i = 0; i < n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
+ } else
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "cache line size not set. Driver may not function\n");
+
+ /* Apply R_ERR on DMA activate FIS errata workaround */
+ if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ int cnt;
+
+ for (i = 0, cnt = 0; i < n_ports; i++) {
+ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+ if ((tmp & 0x3) != 0x01)
+ continue;
+ if (!cnt)
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying R_ERR on DMA activate "
+ "FIS errata fix\n");
+ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+ cnt++;
+ }
+ }
+
+ if (n_ports == 4) {
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + sil_port[2].bmdma);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + sil_port[2].bmdma);
+ }
+}
+
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -535,8 +584,6 @@ static int sil_init_one (struct pci_dev
int rc;
unsigned int i;
int pci_dev_busy = 0;
- u32 tmp;
- u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -595,42 +642,8 @@ static int sil_init_one (struct pci_dev
ata_std_ports(&probe_ent->port[i]);
}
- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < probe_ent->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
-
- /* Apply R_ERR on DMA activate FIS errata workaround */
- if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
- int cnt;
-
- for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
- if ((tmp & 0x3) != 0x01)
- continue;
- if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
- cnt++;
- }
- }
-
- if (ent->driver_data == sil_3114) {
- /* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + sil_port[2].bmdma);
- if ((tmp & SIL_INTR_STEERING) == 0)
- writel(tmp | SIL_INTR_STEERING,
- mmio_base + sil_port[2].bmdma);
- }
+ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ mmio_base);
pci_set_master(pdev);
@@ -650,6 +663,16 @@ err_out:
return rc;
}
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+ sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
+ host_set->mmio_base);
+
+ return ata_pci_device_resume(pdev);
+}
+
static int __init sil_init(void)
{
return pci_module_init(&sil_pci_driver);
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index c8b477c..8c438ba 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/*
* Port registers
@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_p
static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil24_pci_device_resume(struct pci_dev *pdev);
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_drive
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */
+ .suspend = ata_pci_device_suspend,
+ .resume = sil24_pci_device_resume,
};
static struct scsi_host_template sil24_sht = {
@@ -988,6 +992,64 @@ static void sil24_host_stop(struct ata_h
kfree(hpriv);
}
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+ unsigned long host_flags,
+ void __iomem *host_base,
+ void __iomem *port_base)
+{
+ u32 tmp;
+ int i;
+
+ /* GPIO off */
+ writel(0, host_base + HOST_FLASH_CMD);
+
+ /* clear global reset & mask interrupts during initialization */
+ writel(0, host_base + HOST_CTRL);
+
+ /* init ports */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+ /* Initial PHY setting */
+ writel(0x20c, port + PORT_PHY_CFG);
+
+ /* Clear port RST */
+ tmp = readl(port + PORT_CTRL_STAT);
+ if (tmp & PORT_CS_PORT_RST) {
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
+ if (tmp & PORT_CS_PORT_RST)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to clear port RST\n");
+ }
+
+ /* Configure IRQ WoC */
+ if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* Zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* Clear port multiplier enable and resume bits */
+ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+ }
+
+ /* Turn on interrupts */
+ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1076,9 +1138,6 @@ static int sil24_init_one(struct pci_dev
}
}
- /* GPIO off */
- writel(0, host_base + HOST_FLASH_CMD);
-
/* Apply workaround for completion IRQ loss on PCI-X errata */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL);
@@ -1090,56 +1149,18 @@ static int sil24_init_one(struct pci_dev
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
- /* clear global reset & mask interrupts during initialization */
- writel(0, host_base + HOST_CTRL);
-
for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
- unsigned long portu = (unsigned long)port;
+ unsigned long portu =
+ (unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
-
- /* Initial PHY setting */
- writel(0x20c, port + PORT_PHY_CFG);
-
- /* Clear port RST */
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_PORT_RST) {
- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_PORT_RST,
- PORT_CS_PORT_RST, 10, 100);
- if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to clear port RST\n");
- }
-
- /* Configure IRQ WoC */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
- /* Turn on interrupts */
- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ host_base, port_base);
pci_set_master(pdev);
@@ -1162,6 +1183,21 @@ static int sil24_init_one(struct pci_dev
return rc;
}
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+ struct sil24_host_priv *hpriv = host_set->private_data;
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+ sil24_init_controller(pdev, host_set->n_ports,
+ host_set->ports[0]->flags,
+ hpriv->host_base, hpriv->port_base);
+
+ return ata_pci_device_resume(pdev);
+}
+
static int __init sil24_init(void)
{
return pci_module_init(&sil24_pci_driver);
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index 7f86441..58a60ef 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -219,8 +219,8 @@ static const struct ata_port_info pdc_po
{
.sht = &pdc_sata_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
+ ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index c6975c5..44fc057 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -142,7 +142,7 @@ static const struct ata_port_operations
static struct ata_port_info svia_port_info = {
.sht = &svia_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
.udma_mask = 0x7f,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 61eea57..267f3d8 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -148,31 +148,31 @@ enum {
ATA_FLAG_SATA = (1 << 1),
ATA_FLAG_NO_LEGACY = (1 << 2), /* no legacy mode check */
ATA_FLAG_MMIO = (1 << 3), /* use MMIO, not PIO */
- ATA_FLAG_SRST = (1 << 4), /* (obsolete) use ATA SRST, not E.D.D. */
- ATA_FLAG_SATA_RESET = (1 << 5), /* (obsolete) use COMRESET */
- ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */
- ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */
- ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */
- ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD
+ ATA_FLAG_SATA_RESET = (1 << 4), /* (obsolete) use COMRESET */
+ ATA_FLAG_NO_ATAPI = (1 << 5), /* No ATAPI support */
+ ATA_FLAG_PIO_DMA = (1 << 6), /* PIO cmds via DMA */
+ ATA_FLAG_PIO_LBA48 = (1 << 7), /* Host DMA engine is LBA28 only */
+ ATA_FLAG_PIO_POLLING = (1 << 8), /* use polling PIO if LLD
* doesn't handle PIO interrupts */
- ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */
- ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
- ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
+ ATA_FLAG_NCQ = (1 << 9), /* host supports NCQ */
+ ATA_FLAG_HRST_TO_RESUME = (1 << 10), /* hardreset to resume phy */
+ ATA_FLAG_SKIP_D2H_BSY = (1 << 11), /* can't wait for the first D2H
* Register FIS clearing BSY */
- ATA_FLAG_DEBUGMSG = (1 << 13),
- ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
+ ATA_FLAG_DEBUGMSG = (1 << 12),
+ ATA_FLAG_FLUSH_PORT_TASK = (1 << 13), /* flush port task */
- ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
- ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
- ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
- ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
- ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */
- ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */
- ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */
+ ATA_FLAG_EH_PENDING = (1 << 14), /* EH pending */
+ ATA_FLAG_EH_IN_PROGRESS = (1 << 15), /* EH in progress */
+ ATA_FLAG_FROZEN = (1 << 16), /* port is frozen */
+ ATA_FLAG_RECOVERED = (1 << 17), /* recovery action performed */
+ ATA_FLAG_LOADING = (1 << 18), /* boot/loading probe */
+ ATA_FLAG_UNLOADING = (1 << 19), /* module is unloading */
+ ATA_FLAG_SCSI_HOTPLUG = (1 << 20), /* SCSI hotplug scheduled */
- ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */
- ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */
+ ATA_FLAG_DISABLED = (1 << 21), /* port is disabled, ignore it */
+ ATA_FLAG_SUSPENDED = (1 << 22), /* port is suspended (power) */
+ ATA_FLAG_PM_PENDING = (1 << 23), /* PM event pending */
/* bits 24:31 of ap->flags are reserved for LLDD specific flags */
@@ -247,6 +247,7 @@ enum {
ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2),
+ ATA_EH_SPINUP = (1 << 3),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
@@ -356,7 +357,8 @@ struct ata_host_set {
unsigned long flags;
int simplex_claimed; /* Keep seperate in case we
ever need to do this locked */
- struct ata_port * ports[0];
+ struct ata_host_set *next; /* for legacy mode */
+ struct ata_port *ports[0];
};
struct ata_queued_cmd {
@@ -530,6 +532,9 @@ struct ata_port {
struct list_head eh_done_q;
wait_queue_head_t eh_wait_q;
+ pm_message_t pm_mesg;
+ int pm_result;
+
void *private_data;
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -584,6 +589,9 @@ struct ata_port_operations {
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
+ int (*suspend) (struct ata_port *ap, pm_message_t mesg);
+ int (*resume) (struct ata_port *ap);
+
int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap);
@@ -657,10 +665,6 @@ extern int sata_scr_write(struct ata_por
extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap);
-extern int ata_scsi_device_resume(struct scsi_device *);
-extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
-extern int ata_device_resume(struct ata_device *);
-extern int ata_device_suspend(struct ata_device *, pm_message_t state);
extern int ata_ratelimit(void);
extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat,
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-13 8:54 ` zhao, forrest
@ 2006-06-13 9:15 ` Tejun Heo
0 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-13 9:15 UTC (permalink / raw)
To: zhao, forrest; +Cc: jgarzik, lkml, axboe, alan, linux-ide
zhao, forrest wrote:
> On Tue, 2006-06-13 at 18:00 +0900, Tejun Heo wrote:
>> If ata_pci_device_suspend/resume() do things incorrect for a
>> controller(), export ata_host_set_suspend/resume() and call those from
>> LLD's suspend/resume() routines.
>>
>
> OK. I'll export them in the upcoming AHCI suspend/resume patches.
Hmmm... sil/sil24 are currently initialize controller before they
restore power state, which is wrong. I'll fix that. Thanks for raising
the issue.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: rolled up patch for new Power Management for libata
2006-06-13 9:09 ` rolled up patch for " Tejun Heo
@ 2006-06-13 10:38 ` Jens Axboe
2006-06-19 5:46 ` Jens Axboe
0 siblings, 1 reply; 39+ messages in thread
From: Jens Axboe @ 2006-06-13 10:38 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, forrest.zhao, alan, linux-ide
On Tue, Jun 13 2006, Tejun Heo wrote:
> This is a rolled up version of new-pm patchset for testing as
> requested by Jens.
Patch works great for me. Only tested one resume cycle so far, but it
worked and was much quicker than before.
--
Jens Axboe
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-13 8:56 ` Tejun Heo
@ 2006-06-13 11:59 ` Jeff Garzik
0 siblings, 0 replies; 39+ messages in thread
From: Jeff Garzik @ 2006-06-13 11:59 UTC (permalink / raw)
To: Tejun Heo; +Cc: zhao, forrest, lkml, axboe, alan, linux-ide
Tejun Heo wrote:
> Please read ata_pci_init_one() and ata_pci_init_legacy_port() in
> libata-bmdma.c. It's for IDE controllers in legacy mode (not native
> PCI) mode.
Just to be picky: ata_pci_init_one() is for native or legacy mode.
ata_pci_init_legacy_port() is [obviously] only referring to legacy mode.
Jeff
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP
2006-06-12 15:50 ` [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP Tejun Heo
@ 2006-06-14 1:18 ` Jeff Garzik
2006-06-14 15:02 ` Tejun Heo
0 siblings, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2006-06-14 1:18 UTC (permalink / raw)
To: Tejun Heo; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
Tejun Heo wrote:
> Implement new EH action ATA_EH_SPINUP. This will be used by new PM
> implementation.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
This patch further reinforces something I've been thinking about, as I
watch the EH grow: these EH actions really should be separated into
small, discrete operations. Then the EH "driver" will push discrete
operations onto an execution stack.
It's always getting tough to follow ata_eh_recover() and ata_eh_reset()
's code through multiple iterations of recovery. This patch
(ata_eh_spinup) also illustrates how difficult it would be if the
ordering of these operations ever needed to change.
So, I'm not NAK'ing the patch, just throwing out a 'caution' sign. :)
I've often thought something along the lines of a list of tasks
("eh_op_list"), for when a port is frozen and doing EH:
ata_eh_freeze()
ata_eh_push(ap, EH_OP_RESET_BUS, ...)
ata_eh_push(ap, EH_OP_SPINUP, ...)
ata_eh_push(ap, EH_OP_CONFIGURE, ...)
ata_eh_push(ap, EH_OP_SET_MODE, ...)
ata_eh_run()
ata_eh_thaw()
would be nice. A discrete operation would handle its own discrete
operation, prepend and append other operations to eh_op_list, or
optionally cause the engine to fail, and return immediately.
Jeff
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCHSET] new Power Management for libata
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
` (12 preceding siblings ...)
2006-06-13 9:09 ` rolled up patch for " Tejun Heo
@ 2006-06-14 1:25 ` Jeff Garzik
2006-06-14 13:46 ` Tejun Heo
13 siblings, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2006-06-14 1:25 UTC (permalink / raw)
To: Tejun Heo; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
Tejun Heo wrote:
> Hello, all.
>
> This patchset implements new Power Management for libata. Currently,
> only controller-wide suspend and resume are supported. No per-device
> power management yet. Both memsleep and disksleep work on supported
> controllers.
I suppose this is just an RFC?
We don't want to lose to SCSI device suspend, so merging that would be a
regression AFAICS? While we're still married to the SCSI layer, we need
to do suspend through sd.c and similar paths.
I also wonder if any developers or users make use of the ability to
suspend/resume individual pieces of hardware, as is (somewhat) supported
in ata_piix in 2.6.17-rcX.
Jeff
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
` (3 preceding siblings ...)
2006-06-13 8:37 ` zhao, forrest
@ 2006-06-14 7:56 ` zhao, forrest
2006-06-14 13:29 ` Tejun Heo
4 siblings, 1 reply; 39+ messages in thread
From: zhao, forrest @ 2006-06-14 7:56 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
> + */
> +static void ata_eh_handle_resume(struct ata_port *ap)
> +{
> + unsigned long flags;
> + int rc = 0;
> +
> + spin_lock_irqsave(&ap->host_set->lock, flags);
> + if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
> + !(ap->flags & ATA_FLAG_SUSPENDED) ||
> + ap->pm_mesg.event != PM_EVENT_ON) {
> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
> + return;
> + }
> + ap->flags &= ~ATA_FLAG_PM_PENDING;
> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
> +
> + if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND) {
> + struct ata_eh_context *ehc = &ap->eh_context;
> +
> + ehc->i.action |= ATA_EH_SPINUP;
> + ata_ehi_hotplugged(&ehc->i);
> + }
> +
> + if (ap->ops->resume)
> + rc = ap->ops->resume(ap);
> +
> + spin_lock_irqsave(&ap->host_set->lock, flags);
> + ap->flags &= ~ATA_FLAG_SUSPENDED;
> + ap->pm_result = rc;
> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
> +}
I ported AHCI suspend/resume patches against your new PM framework. At
first resume from memsleep took 65 seconds to go through soft-reset,
hard-reset; then after I removed line
"if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND)" in
ata_eh_handle_resume(), AHCI can resume from memsleep in a few seconds.
After inserting a printk(), I found the "ap->host_set->dev->power.
power_state.event" is always 0(PM_EVENT_ON).
I think we can introduce a new field in struct ata_port to record the
power_state.event, which was passed in suspend callback.
Thanks,
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-14 7:56 ` zhao, forrest
@ 2006-06-14 13:29 ` Tejun Heo
2006-06-15 1:33 ` zhao, forrest
0 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-14 13:29 UTC (permalink / raw)
To: zhao, forrest; +Cc: jgarzik, lkml, axboe, alan, linux-ide
zhao, forrest wrote:
> On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
>> + */
>> +static void ata_eh_handle_resume(struct ata_port *ap)
>> +{
>> + unsigned long flags;
>> + int rc = 0;
>> +
>> + spin_lock_irqsave(&ap->host_set->lock, flags);
>> + if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
>> + !(ap->flags & ATA_FLAG_SUSPENDED) ||
>> + ap->pm_mesg.event != PM_EVENT_ON) {
>> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
>> + return;
>> + }
>> + ap->flags &= ~ATA_FLAG_PM_PENDING;
>> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
>> +
>> + if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND) {
>> + struct ata_eh_context *ehc = &ap->eh_context;
>> +
>> + ehc->i.action |= ATA_EH_SPINUP;
>> + ata_ehi_hotplugged(&ehc->i);
>> + }
>> +
>> + if (ap->ops->resume)
>> + rc = ap->ops->resume(ap);
>> +
>> + spin_lock_irqsave(&ap->host_set->lock, flags);
>> + ap->flags &= ~ATA_FLAG_SUSPENDED;
>> + ap->pm_result = rc;
>> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
>> +}
>
> I ported AHCI suspend/resume patches against your new PM framework. At
> first resume from memsleep took 65 seconds to go through soft-reset,
> hard-reset; then after I removed line
> "if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND)" in
> ata_eh_handle_resume(), AHCI can resume from memsleep in a few seconds.
> After inserting a printk(), I found the "ap->host_set->dev->power.
> power_state.event" is always 0(PM_EVENT_ON).
Can you post the AHCI patch you did? The suspend routine is supposed to
set power state to PM_EVENT_SUSPEND on memsleep such that resume can
notice it's resuming from actual suspend.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCHSET] new Power Management for libata
2006-06-14 1:25 ` [PATCHSET] " Jeff Garzik
@ 2006-06-14 13:46 ` Tejun Heo
2006-06-19 5:18 ` zhao, forrest
0 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-14 13:46 UTC (permalink / raw)
To: Jeff Garzik; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
Jeff Garzik wrote:
> Tejun Heo wrote:
>> Hello, all.
>>
>> This patchset implements new Power Management for libata. Currently,
>> only controller-wide suspend and resume are supported. No per-device
>> power management yet. Both memsleep and disksleep work on supported
>> controllers.
>
> I suppose this is just an RFC?
Well, not really.
> We don't want to lose to SCSI device suspend, so merging that would be a
> regression AFAICS? While we're still married to the SCSI layer, we need
> to do suspend through sd.c and similar paths.
>
> I also wonder if any developers or users make use of the ability to
> suspend/resume individual pieces of hardware, as is (somewhat) supported
> in ata_piix in 2.6.17-rcX.
At first I thought about implementing that and asked Pavel about how to
discern between partial PM and system-wide PM so that libata can do
things bus-wide on system-wide PM event. Pavel's response was...
"> And, one more things. As written in the first mail, for libata, it
> > would be nice to know if a device suspend is due to runtime PM event
> > (per-device) or system wide suspend. What do you think about this?
If
> > you agree, what method do you recommend to determine that?
Currently, runtime pm is unsupported/broken; so any request can be
thought as system pm.
Pavel"
So, I determined to ignore per-device PM for the time being. I think I
can still implement it but I'm a bit skeptical about its usefulness. I
personally haven't seen any user of partial power management using sysfs
interface. IIRC, dynamic power management on IDE disks from userspace
is done by issuing STANDBY using raw command interface.
What do you think?
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP
2006-06-14 1:18 ` Jeff Garzik
@ 2006-06-14 15:02 ` Tejun Heo
2006-06-14 15:25 ` Alan Cox
0 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2006-06-14 15:02 UTC (permalink / raw)
To: Jeff Garzik; +Cc: lkml, axboe, forrest.zhao, alan, linux-ide
Jeff Garzik wrote:
> Tejun Heo wrote:
>> Implement new EH action ATA_EH_SPINUP. This will be used by new PM
>> implementation.
>>
>> Signed-off-by: Tejun Heo <htejun@gmail.com>
>
> This patch further reinforces something I've been thinking about, as I
> watch the EH grow: these EH actions really should be separated into
> small, discrete operations. Then the EH "driver" will push discrete
> operations onto an execution stack.
>
> It's always getting tough to follow ata_eh_recover() and ata_eh_reset()
> 's code through multiple iterations of recovery. This patch
> (ata_eh_spinup) also illustrates how difficult it would be if the
> ordering of these operations ever needed to change.
>
> So, I'm not NAK'ing the patch, just throwing out a 'caution' sign. :)
>
> I've often thought something along the lines of a list of tasks
> ("eh_op_list"), for when a port is frozen and doing EH:
> ata_eh_freeze()
> ata_eh_push(ap, EH_OP_RESET_BUS, ...)
> ata_eh_push(ap, EH_OP_SPINUP, ...)
> ata_eh_push(ap, EH_OP_CONFIGURE, ...)
> ata_eh_push(ap, EH_OP_SET_MODE, ...)
> ata_eh_run()
> ata_eh_thaw()
>
> would be nice. A discrete operation would handle its own discrete
> operation, prepend and append other operations to eh_op_list, or
> optionally cause the engine to fail, and return immediately.
At first, I thought many different controllers would use different EH
drive routines, so I put all EH operations in separate functions and
grouped them into several larger steps - currently autopsy, report,
recover and finish.
In earlier implementation, sil24 and ahci actually had to implement
their own drive routine calling those ops and doing private things
in-between, but as EH implementation matures all those are handled by
feeding proper information into the core EH. I'm looking at other
drivers to convert them to new EH but haven't found any driver which the
current standard EH can't handle. Although I haven't looked at all
drivers yet and some of them may indeed need such specialized
implementation.
I think it boils down to the fact that the core EH is more about ATA
devices than it's about controllers. Controllers vary from one another
but ATA/ATAPI devices are the same old ATA/ATAPI devices whatever the
controller is. So, as long as LLD has a way to feed enough information
to core EH about the state of the attached device && core EH's
controller interface (freeze, thaw & resets) fits the controller to
acceptable degree, core EH doesn't have to be different across different
LLDs.
IMHO, it's best to keep single unified implementation until it begins to
pick up many special cases to deal with specific LLDs. I think we're
still in the safe regarding that. If we pass that point, I think we
should start by implementing private drive routines in LLDs before
making core EH programmable. After several such tries, the requirements
for programmable EH would be much clearer and we would be able to do
much better job of implementing something which is flexible enough but
still as simple as possible.
To sum up...
* Until now, unified EH seems good enough. In fact, not a single driver
needs to go further than calling ata_do_eh() w/ proper callbacks.
* I agree that it would be nice to have programmable EH, but let's do it
when it's actually needed. It seems that early implementation of
complex infrastructure seldom ends up in something pleasant to look at.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP
2006-06-14 15:02 ` Tejun Heo
@ 2006-06-14 15:25 ` Alan Cox
0 siblings, 0 replies; 39+ messages in thread
From: Alan Cox @ 2006-06-14 15:25 UTC (permalink / raw)
To: Tejun Heo; +Cc: Jeff Garzik, lkml, axboe, forrest.zhao, linux-ide
> * Until now, unified EH seems good enough. In fact, not a single driver
> needs to go further than calling ata_do_eh() w/ proper callbacks.
This has been shown to be fairly true for the old IDE as well. Other
than the years old unfixed promise crash (for which patches exist) the
core error recovery doesn't need to do anything in a different order for
different devices.
For PATA controllerrs using the traditional i/o API the variances are
small and normally around the resetting of the bus, and whether you also
have to whack the state machine with a large hammer to get it back into
shape after an error case, or whether hardware does it.
The promise is "special" purely because if you reset the state machine
then read from the data port before you do another operation you hang
the box, and that sequence of events is a failure of the old IDE design
rather than a "different" ordering of events.
Alan
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-14 13:29 ` Tejun Heo
@ 2006-06-15 1:33 ` zhao, forrest
2006-06-15 3:41 ` Tejun Heo
0 siblings, 1 reply; 39+ messages in thread
From: zhao, forrest @ 2006-06-15 1:33 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, axboe, alan, linux-ide
On Wed, 2006-06-14 at 22:29 +0900, Tejun Heo wrote:
> zhao, forrest wrote:
> > On Tue, 2006-06-13 at 00:50 +0900, Tejun Heo wrote:
> >> + */
> >> +static void ata_eh_handle_resume(struct ata_port *ap)
> >> +{
> >> + unsigned long flags;
> >> + int rc = 0;
> >> +
> >> + spin_lock_irqsave(&ap->host_set->lock, flags);
> >> + if (!(ap->flags & ATA_FLAG_PM_PENDING) ||
> >> + !(ap->flags & ATA_FLAG_SUSPENDED) ||
> >> + ap->pm_mesg.event != PM_EVENT_ON) {
> >> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
> >> + return;
> >> + }
> >> + ap->flags &= ~ATA_FLAG_PM_PENDING;
> >> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
> >> +
> >> + if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND) {
> >> + struct ata_eh_context *ehc = &ap->eh_context;
> >> +
> >> + ehc->i.action |= ATA_EH_SPINUP;
> >> + ata_ehi_hotplugged(&ehc->i);
> >> + }
> >> +
> >> + if (ap->ops->resume)
> >> + rc = ap->ops->resume(ap);
> >> +
> >> + spin_lock_irqsave(&ap->host_set->lock, flags);
> >> + ap->flags &= ~ATA_FLAG_SUSPENDED;
> >> + ap->pm_result = rc;
> >> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
> >> +}
> >
> > I ported AHCI suspend/resume patches against your new PM framework. At
> > first resume from memsleep took 65 seconds to go through soft-reset,
> > hard-reset; then after I removed line
> > "if (ap->host_set->dev->power.power_state.event == PM_EVENT_SUSPEND)" in
> > ata_eh_handle_resume(), AHCI can resume from memsleep in a few seconds.
> > After inserting a printk(), I found the "ap->host_set->dev->power.
> > power_state.event" is always 0(PM_EVENT_ON).
>
> Can you post the AHCI patch you did? The suspend routine is supposed to
> set power state to PM_EVENT_SUSPEND on memsleep such that resume can
> notice it's resuming from actual suspend.
Yeah, on memsleep host_set->dev->power.power_state is set to
PM_EVENT_SUSPEND in ata_host_set_suspend(). Then during resume process,
firstly ata_host_set_resume() is called, in which host_set->dev->power.
power_state is set to PMSG_ON, then ata_eh_handle_resume() is called
later. This is the reason why ap->host_set->dev->power.power_state.event
is 0 in ata_eh_handle_resume(). This is a race condition.
Thanks,
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH 06/10] libata: implement new Power Management framework
2006-06-15 1:33 ` zhao, forrest
@ 2006-06-15 3:41 ` Tejun Heo
0 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-15 3:41 UTC (permalink / raw)
To: zhao, forrest; +Cc: jgarzik, lkml, axboe, alan, linux-ide
zhao, forrest wrote:
> Yeah, on memsleep host_set->dev->power.power_state is set to
> PM_EVENT_SUSPEND in ata_host_set_suspend(). Then during resume process,
> firstly ata_host_set_resume() is called, in which host_set->dev->power.
> power_state is set to PMSG_ON, then ata_eh_handle_resume() is called
> later. This is the reason why ap->host_set->dev->power.power_state.event
> is 0 in ata_eh_handle_resume(). This is a race condition.
Yeap, you're right. Hmmm.. weird. I haven't noticed that race
condition during my tests. I think we can use a DFLAG to mark that a
device had been spun down. Thanks for spotting it.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCHSET] new Power Management for libata
2006-06-14 13:46 ` Tejun Heo
@ 2006-06-19 5:18 ` zhao, forrest
2006-06-19 8:46 ` Tejun Heo
0 siblings, 1 reply; 39+ messages in thread
From: zhao, forrest @ 2006-06-19 5:18 UTC (permalink / raw)
To: Tejun Heo; +Cc: Jeff Garzik, lkml, axboe, alan, linux-ide
On Wed, 2006-06-14 at 22:46 +0900, Tejun Heo wrote:
> Jeff Garzik wrote:
> > Tejun Heo wrote:
> >> Hello, all.
> >>
> >> This patchset implements new Power Management for libata. Currently,
> >> only controller-wide suspend and resume are supported. No per-device
> >> power management yet. Both memsleep and disksleep work on supported
> >> controllers.
> >
> > I suppose this is just an RFC?
>
> Well, not really.
>
> > We don't want to lose to SCSI device suspend, so merging that would be a
> > regression AFAICS? While we're still married to the SCSI layer, we need
> > to do suspend through sd.c and similar paths.
> >
> > I also wonder if any developers or users make use of the ability to
> > suspend/resume individual pieces of hardware, as is (somewhat) supported
> > in ata_piix in 2.6.17-rcX.
>
> At first I thought about implementing that and asked Pavel about how to
> discern between partial PM and system-wide PM so that libata can do
> things bus-wide on system-wide PM event. Pavel's response was...
>
> "> And, one more things. As written in the first mail, for libata, it
> > > would be nice to know if a device suspend is due to runtime PM event
> > > (per-device) or system wide suspend. What do you think about this?
> If
> > > you agree, what method do you recommend to determine that?
>
> Currently, runtime pm is unsupported/broken; so any request can be
> thought as system pm.
> Pavel"
>
> So, I determined to ignore per-device PM for the time being. I think I
> can still implement it but I'm a bit skeptical about its usefulness. I
> personally haven't seen any user of partial power management using sysfs
> interface. IIRC, dynamic power management on IDE disks from userspace
> is done by issuing STANDBY using raw command interface.
>
> What do you think?
Jeff and Tejun,
Have we achieved a consensus about this new PM patches? The AHCI
suspend/resume patch and ACPI-SATA patch will definitely depend on this
new PM.
Thanks,
Forrest
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: rolled up patch for new Power Management for libata
2006-06-13 10:38 ` Jens Axboe
@ 2006-06-19 5:46 ` Jens Axboe
0 siblings, 0 replies; 39+ messages in thread
From: Jens Axboe @ 2006-06-19 5:46 UTC (permalink / raw)
To: Tejun Heo; +Cc: jgarzik, lkml, forrest.zhao, alan, linux-ide
On Tue, Jun 13 2006, Jens Axboe wrote:
> On Tue, Jun 13 2006, Tejun Heo wrote:
> > This is a rolled up version of new-pm patchset for testing as
> > requested by Jens.
>
> Patch works great for me. Only tested one resume cycle so far, but it
> worked and was much quicker than before.
Notebook hasn't been booted since, so I can confirm it's very reliable.
No issues seen so far, and I'm enjoying the snappier resume.
--
Jens Axboe
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCHSET] new Power Management for libata
2006-06-19 5:18 ` zhao, forrest
@ 2006-06-19 8:46 ` Tejun Heo
0 siblings, 0 replies; 39+ messages in thread
From: Tejun Heo @ 2006-06-19 8:46 UTC (permalink / raw)
To: zhao, forrest; +Cc: Jeff Garzik, lkml, axboe, alan, linux-ide
> Jeff and Tejun,
>
> Have we achieved a consensus about this new PM patches? The AHCI
> suspend/resume patch and ACPI-SATA patch will definitely depend on this
> new PM.
The consensus seems to be me doing another round of this patchset w/
per-dev PM support. I'm currently working on it. I don't think it will
take more than a few days.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 39+ messages in thread
end of thread, other threads:[~2006-06-19 8:46 UTC | newest]
Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-12 15:50 [PATCHSET] new Power Management for libata Tejun Heo
2006-06-12 15:50 ` [PATCH 01/10] libata: power down controller only on PMSG_SUSPEND Tejun Heo
2006-06-12 16:32 ` Jeff Garzik
2006-06-13 2:20 ` Tejun Heo
2006-06-12 15:50 ` [PATCH 03/10] libata: move ata_do_simple_cmd() right below ata_exec_internal() Tejun Heo
2006-06-12 15:50 ` [PATCH 02/10] libata: kill per-device PM Tejun Heo
2006-06-12 15:50 ` [PATCH 04/10] libata: update ata_do_simple_cmd() Tejun Heo
2006-06-12 15:50 ` [PATCH 09/10] sata_sil24: separate out sil24_init_controller() Tejun Heo
2006-06-12 15:50 ` [PATCH 10/10] sata_sil24: add suspend/sleep support Tejun Heo
2006-06-12 15:50 ` [PATCH 08/10] sata_sil: " Tejun Heo
2006-06-12 15:50 ` [PATCH 07/10] sata_sil: separate out sil_init_controller() Tejun Heo
2006-06-12 15:50 ` [PATCH 05/10] libata: implement new EH action ATA_EH_SPINUP Tejun Heo
2006-06-14 1:18 ` Jeff Garzik
2006-06-14 15:02 ` Tejun Heo
2006-06-14 15:25 ` Alan Cox
2006-06-12 15:50 ` [PATCH 06/10] libata: implement new Power Management framework Tejun Heo
2006-06-12 16:34 ` Alan Cox
2006-06-13 2:08 ` Tejun Heo
2006-06-13 6:25 ` zhao, forrest
2006-06-13 8:56 ` Tejun Heo
2006-06-13 11:59 ` Jeff Garzik
2006-06-13 8:17 ` zhao, forrest
2006-06-13 9:00 ` Tejun Heo
2006-06-13 8:54 ` zhao, forrest
2006-06-13 9:15 ` Tejun Heo
2006-06-13 8:37 ` zhao, forrest
2006-06-14 7:56 ` zhao, forrest
2006-06-14 13:29 ` Tejun Heo
2006-06-15 1:33 ` zhao, forrest
2006-06-15 3:41 ` Tejun Heo
2006-06-12 15:57 ` [PATCHSET] new Power Management for libata Tejun Heo
2006-06-13 6:28 ` zhao, forrest
2006-06-13 9:09 ` rolled up patch for " Tejun Heo
2006-06-13 10:38 ` Jens Axboe
2006-06-19 5:46 ` Jens Axboe
2006-06-14 1:25 ` [PATCHSET] " Jeff Garzik
2006-06-14 13:46 ` Tejun Heo
2006-06-19 5:18 ` zhao, forrest
2006-06-19 8:46 ` Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).